109 |
109 |
110 text {* |
110 text {* |
111 |
111 |
112 During development you might find it necessary to inspect some data |
112 During development you might find it necessary to inspect some data |
113 in your code. This can be done in a ``quick-and-dirty'' fashion using |
113 in your code. This can be done in a ``quick-and-dirty'' fashion using |
114 the function @{ML [indexc] "writeln"}. For example |
114 the function @{ML [index] "writeln"}. For example |
115 |
115 |
116 @{ML_response_fake [display,gray] "writeln \"any string\"" "\"any string\""} |
116 @{ML_response_fake [display,gray] "writeln \"any string\"" "\"any string\""} |
117 |
117 |
118 will print out @{text [quotes] "any string"} inside the response buffer |
118 will print out @{text [quotes] "any string"} inside the response buffer |
119 of Isabelle. This function expects a string as argument. If you develop under PolyML, |
119 of Isabelle. This function expects a string as argument. If you develop under PolyML, |
120 then there is a convenient, though again ``quick-and-dirty'', method for |
120 then there is a convenient, though again ``quick-and-dirty'', method for |
121 converting values into strings, namely the function @{ML PolyML.makestring}: |
121 converting values into strings, namely the function @{ML PolyML.makestring}: |
122 |
122 |
123 @{ML_response_fake [display,gray] "writeln (PolyML.makestring 1)" "\"1\""} |
123 @{ML_response_fake [display,gray] "writeln (PolyML.makestring 1)" "\"1\""} |
124 |
124 |
125 However, @{ML makestring} only works if the type of what is converted is monomorphic |
125 However, @{ML [index] makestring} only works if the type of what is converted is monomorphic |
126 and not a function. |
126 and not a function. |
127 |
127 |
128 The function @{ML "writeln"} should only be used for testing purposes, because any |
128 The function @{ML "writeln"} should only be used for testing purposes, because any |
129 output this function generates will be overwritten as soon as an error is |
129 output this function generates will be overwritten as soon as an error is |
130 raised. For printing anything more serious and elaborate, the |
130 raised. For printing anything more serious and elaborate, the |
131 function @{ML tracing} is more appropriate. This function writes all output into |
131 function @{ML [index] tracing} is more appropriate. This function writes all output into |
132 a separate tracing buffer. For example: |
132 a separate tracing buffer. For example: |
133 |
133 |
134 @{ML_response_fake [display,gray] "tracing \"foo\"" "\"foo\""} |
134 @{ML_response_fake [display,gray] "tracing \"foo\"" "\"foo\""} |
135 |
135 |
136 It is also possible to redirect the ``channel'' where the string @{text "foo"} is |
136 It is also possible to redirect the ``channel'' where the string @{text "foo"} is |
153 |
153 |
154 text {* |
154 text {* |
155 Calling @{ML "redirect_tracing"} with @{ML "(TextIO.openOut \"foo.bar\")"} |
155 Calling @{ML "redirect_tracing"} with @{ML "(TextIO.openOut \"foo.bar\")"} |
156 will cause that all tracing information is printed into the file @{text "foo.bar"}. |
156 will cause that all tracing information is printed into the file @{text "foo.bar"}. |
157 |
157 |
158 You can print out error messages with the function @{ML error}; for example: |
158 You can print out error messages with the function @{ML [index] error}; for example: |
159 |
159 |
160 @{ML_response_fake [display,gray] "if 0=1 then true else (error \"foo\")" |
160 @{ML_response_fake [display,gray] "if 0=1 then true else (error \"foo\")" |
161 "Exception- ERROR \"foo\" raised |
161 "Exception- ERROR \"foo\" raised |
162 At command \"ML\"."} |
162 At command \"ML\"."} |
163 |
163 |
164 (FIXME Mention how to work with @{ML Toplevel.debug} and @{ML Toplevel.profiling}.) |
164 (FIXME Mention how to work with @{ML [index] debug in Toplevel} and |
|
165 @{ML [index] profiling in Toplevel}.) |
165 *} |
166 *} |
166 |
167 |
167 (* |
168 (* |
168 ML {* reset Toplevel.debug *} |
169 ML {* reset Toplevel.debug *} |
169 |
170 |
181 text {* |
182 text {* |
182 Most often you want to inspect data of type @{ML_type term}, @{ML_type cterm} |
183 Most often you want to inspect data of type @{ML_type term}, @{ML_type cterm} |
183 or @{ML_type thm}. Isabelle contains elaborate pretty-printing functions for printing |
184 or @{ML_type thm}. Isabelle contains elaborate pretty-printing functions for printing |
184 them (see Section \ref{sec:pretty}), |
185 them (see Section \ref{sec:pretty}), |
185 but for quick-and-dirty solutions they are far too unwieldy. A simple way to transform |
186 but for quick-and-dirty solutions they are far too unwieldy. A simple way to transform |
186 a term into a string is to use the function @{ML Syntax.string_of_term}. |
187 a term into a string is to use the function @{ML [index] string_of_term in Syntax}. |
187 |
188 |
188 @{ML_response_fake [display,gray] |
189 @{ML_response_fake [display,gray] |
189 "Syntax.string_of_term @{context} @{term \"1::nat\"}" |
190 "Syntax.string_of_term @{context} @{term \"1::nat\"}" |
190 "\"\\^E\\^Fterm\\^E\\^E\\^Fconst\\^Fname=HOL.one_class.one\\^E1\\^E\\^F\\^E\\^E\\^F\\^E\""} |
191 "\"\\^E\\^Fterm\\^E\\^E\\^Fconst\\^Fname=HOL.one_class.one\\^E1\\^E\\^F\\^E\\^E\\^F\\^E\""} |
191 |
192 |
192 This produces a string with some additional information encoded in it. The string |
193 This produces a string with some additional information encoded in it. The string |
193 can be properly printed by using the function @{ML writeln}. |
194 can be properly printed by using the function @{ML [index] writeln}. |
194 |
195 |
195 @{ML_response_fake [display,gray] |
196 @{ML_response_fake [display,gray] |
196 "writeln (Syntax.string_of_term @{context} @{term \"1::nat\"})" |
197 "writeln (Syntax.string_of_term @{context} @{term \"1::nat\"})" |
197 "\"1\""} |
198 "\"1\""} |
198 |
199 |
201 |
202 |
202 ML{*fun string_of_cterm ctxt t = |
203 ML{*fun string_of_cterm ctxt t = |
203 Syntax.string_of_term ctxt (term_of t)*} |
204 Syntax.string_of_term ctxt (term_of t)*} |
204 |
205 |
205 text {* |
206 text {* |
206 In this example the function @{ML term_of} extracts the @{ML_type term} from |
207 In this example the function @{ML [index] term_of} extracts the @{ML_type term} from |
207 a @{ML_type cterm}. If there are more than one @{ML_type cterm}s to be |
208 a @{ML_type cterm}. If there are more than one @{ML_type cterm}s to be |
208 printed, you can use the function @{ML commas} to separate them. |
209 printed, you can use the function @{ML [index] commas} to separate them. |
209 *} |
210 *} |
210 |
211 |
211 ML{*fun string_of_cterms ctxt ts = |
212 ML{*fun string_of_cterms ctxt ts = |
212 commas (map (string_of_cterm ctxt) ts)*} |
213 commas (map (string_of_cterm ctxt) ts)*} |
213 |
214 |
214 text {* |
215 text {* |
215 The easiest way to get the string of a theorem is to transform it |
216 The easiest way to get the string of a theorem is to transform it |
216 into a @{ML_type cterm} using the function @{ML crep_thm}. |
217 into a @{ML_type cterm} using the function @{ML [index] crep_thm}. |
217 *} |
218 *} |
218 |
219 |
219 ML{*fun string_of_thm ctxt thm = |
220 ML{*fun string_of_thm ctxt thm = |
220 string_of_cterm ctxt (#prop (crep_thm thm))*} |
221 string_of_cterm ctxt (#prop (crep_thm thm))*} |
221 |
222 |
227 "writeln (string_of_thm @{context} @{thm conjI})" |
228 "writeln (string_of_thm @{context} @{thm conjI})" |
228 "\<lbrakk>?P; ?Q\<rbrakk> \<Longrightarrow> ?P \<and> ?Q"} |
229 "\<lbrakk>?P; ?Q\<rbrakk> \<Longrightarrow> ?P \<and> ?Q"} |
229 |
230 |
230 In order to improve the readability of theorems we convert |
231 In order to improve the readability of theorems we convert |
231 these schematic variables into free variables using the |
232 these schematic variables into free variables using the |
232 function @{ML Variable.import_thms}. |
233 function @{ML [index] import_thms in Variable}. |
233 *} |
234 *} |
234 |
235 |
235 ML{*fun no_vars ctxt thm = |
236 ML{*fun no_vars ctxt thm = |
236 let |
237 let |
237 val ((_, [thm']), _) = Variable.import_thms true [thm] ctxt |
238 val ((_, [thm']), _) = Variable.import_thms true [thm] ctxt |
264 For beginners perhaps the most puzzling parts in the existing code of Isabelle are |
265 For beginners perhaps the most puzzling parts in the existing code of Isabelle are |
265 the combinators. At first they seem to greatly obstruct the |
266 the combinators. At first they seem to greatly obstruct the |
266 comprehension of the code, but after getting familiar with them, they |
267 comprehension of the code, but after getting familiar with them, they |
267 actually ease the understanding and also the programming. |
268 actually ease the understanding and also the programming. |
268 |
269 |
269 The simplest combinator is @{ML I}, which is just the identity function defined as |
270 The simplest combinator is @{ML [index] I}, which is just the identity function defined as |
270 *} |
271 *} |
271 |
272 |
272 ML{*fun I x = x*} |
273 ML{*fun I x = x*} |
273 |
274 |
274 text {* Another simple combinator is @{ML K}, defined as *} |
275 text {* Another simple combinator is @{ML [index] K}, defined as *} |
275 |
276 |
276 ML{*fun K x = fn _ => x*} |
277 ML{*fun K x = fn _ => x*} |
277 |
278 |
278 text {* |
279 text {* |
279 @{ML K} ``wraps'' a function around the argument @{text "x"}. However, this |
280 @{ML [index] K} ``wraps'' a function around the argument @{text "x"}. However, this |
280 function ignores its argument. As a result, @{ML K} defines a constant function |
281 function ignores its argument. As a result, @{ML K} defines a constant function |
281 always returning @{text x}. |
282 always returning @{text x}. |
282 |
283 |
283 The next combinator is reverse application, @{ML "|>"}, defined as: |
284 The next combinator is reverse application, @{ML [index] "|>"}, defined as: |
284 *} |
285 *} |
285 |
286 |
286 ML{*fun x |> f = f x*} |
287 ML{*fun x |> f = f x*} |
287 |
288 |
288 text {* While just syntactic sugar for the usual function application, |
289 text {* While just syntactic sugar for the usual function application, |
350 |> Syntax.string_of_term @{context} |
351 |> Syntax.string_of_term @{context} |
351 |> writeln" |
352 |> writeln" |
352 "P z za zb"} |
353 "P z za zb"} |
353 |
354 |
354 You can read off this behaviour from how @{ML apply_fresh_args} is |
355 You can read off this behaviour from how @{ML apply_fresh_args} is |
355 coded: in Line 2, the function @{ML fastype_of} calculates the type of the |
356 coded: in Line 2, the function @{ML [index] fastype_of} calculates the type of the |
356 function; @{ML binder_types} in the next line produces the list of argument |
357 function; @{ML [index] binder_types} in the next line produces the list of argument |
357 types (in the case above the list @{text "[nat, int, unit]"}); Line 4 |
358 types (in the case above the list @{text "[nat, int, unit]"}); Line 4 |
358 pairs up each type with the string @{text "z"}; the |
359 pairs up each type with the string @{text "z"}; the |
359 function @{ML variant_frees in Variable} generates for each @{text "z"} a |
360 function @{ML [index] variant_frees in Variable} generates for each @{text "z"} a |
360 unique name avoiding the given @{text f}; the list of name-type pairs is turned |
361 unique name avoiding the given @{text f}; the list of name-type pairs is turned |
361 into a list of variable terms in Line 6, which in the last line is applied |
362 into a list of variable terms in Line 6, which in the last line is applied |
362 by the function @{ML list_comb} to the function. In this last step we have to |
363 by the function @{ML [index] list_comb} to the function. In this last step we have to |
363 use the function @{ML curry}, because @{ML list_comb} expects the function and the |
364 use the function @{ML [index] curry}, because @{ML [index] list_comb} expects the |
364 variables list as a pair. This kind of functions is often needed when |
365 function and the variables list as a pair. This kind of functions is often needed when |
365 constructing terms and the infrastructure helps tremendously to avoid |
366 constructing terms and the infrastructure helps tremendously to avoid |
366 any name clashes. Consider for example: |
367 any name clashes. Consider for example: |
367 |
368 |
368 @{ML_response_fake [display,gray] |
369 @{ML_response_fake [display,gray] |
369 "apply_fresh_args @{term \"za::'a \<Rightarrow> 'b \<Rightarrow> 'c\"} @{context} |
370 "apply_fresh_args @{term \"za::'a \<Rightarrow> 'b \<Rightarrow> 'c\"} @{context} |
370 |> Syntax.string_of_term @{context} |
371 |> Syntax.string_of_term @{context} |
371 |> writeln" |
372 |> writeln" |
372 "za z zb"} |
373 "za z zb"} |
373 |
374 |
374 The combinator @{ML "#>"} is the reverse function composition. It can be |
375 The combinator @{ML [index] "#>"} is the reverse function composition. It can be |
375 used to define the following function |
376 used to define the following function |
376 *} |
377 *} |
377 |
378 |
378 ML{*val inc_by_six = |
379 ML{*val inc_by_six = |
379 (fn x => x + 1) |
380 (fn x => x + 1) |
384 which is the function composed of first the increment-by-one function and then |
385 which is the function composed of first the increment-by-one function and then |
385 increment-by-two, followed by increment-by-three. Again, the reverse function |
386 increment-by-two, followed by increment-by-three. Again, the reverse function |
386 composition allows you to read the code top-down. |
387 composition allows you to read the code top-down. |
387 |
388 |
388 The remaining combinators described in this section add convenience for the |
389 The remaining combinators described in this section add convenience for the |
389 ``waterfall method'' of writing functions. The combinator @{ML tap} allows |
390 ``waterfall method'' of writing functions. The combinator @{ML [index] tap} allows |
390 you to get hold of an intermediate result (to do some side-calculations for |
391 you to get hold of an intermediate result (to do some side-calculations for |
391 instance). The function |
392 instance). The function |
392 |
393 |
393 *} |
394 *} |
394 |
395 |
397 |> tap (fn x => tracing (PolyML.makestring x)) |
398 |> tap (fn x => tracing (PolyML.makestring x)) |
398 |> (fn x => x + 2)*} |
399 |> (fn x => x + 2)*} |
399 |
400 |
400 text {* |
401 text {* |
401 increments the argument first by @{text "1"} and then by @{text "2"}. In the |
402 increments the argument first by @{text "1"} and then by @{text "2"}. In the |
402 middle (Line 3), however, it uses @{ML tap} for printing the ``plus-one'' |
403 middle (Line 3), however, it uses @{ML [index] tap} for printing the ``plus-one'' |
403 intermediate result inside the tracing buffer. The function @{ML tap} can |
404 intermediate result inside the tracing buffer. The function @{ML [index] tap} can |
404 only be used for side-calculations, because any value that is computed |
405 only be used for side-calculations, because any value that is computed |
405 cannot be merged back into the ``main waterfall''. To do this, you can use |
406 cannot be merged back into the ``main waterfall''. To do this, you can use |
406 the next combinator. |
407 the next combinator. |
407 |
408 |
408 The combinator @{ML "`"} (a backtick) is similar to @{ML tap}, but applies a |
409 The combinator @{ML [index] "`"} (a backtick) is similar to @{ML tap}, but applies a |
409 function to the value and returns the result together with the value (as a |
410 function to the value and returns the result together with the value (as a |
410 pair). For example the function |
411 pair). For example the function |
411 *} |
412 *} |
412 |
413 |
413 ML{*fun inc_as_pair x = |
414 ML{*fun inc_as_pair x = |
418 takes @{text x} as argument, and then increments @{text x}, but also keeps |
419 takes @{text x} as argument, and then increments @{text x}, but also keeps |
419 @{text x}. The intermediate result is therefore the pair @{ML "(x + 1, x)" |
420 @{text x}. The intermediate result is therefore the pair @{ML "(x + 1, x)" |
420 for x}. After that, the function increments the right-hand component of the |
421 for x}. After that, the function increments the right-hand component of the |
421 pair. So finally the result will be @{ML "(x + 1, x + 1)" for x}. |
422 pair. So finally the result will be @{ML "(x + 1, x + 1)" for x}. |
422 |
423 |
423 The combinators @{ML "|>>"} and @{ML "||>"} are defined for |
424 The combinators @{ML [index] "|>>"} and @{ML [index] "||>"} are defined for |
424 functions manipulating pairs. The first applies the function to |
425 functions manipulating pairs. The first applies the function to |
425 the first component of the pair, defined as |
426 the first component of the pair, defined as |
426 *} |
427 *} |
427 |
428 |
428 ML{*fun (x, y) |>> f = (f x, y)*} |
429 ML{*fun (x, y) |>> f = (f x, y)*} |
432 *} |
433 *} |
433 |
434 |
434 ML{*fun (x, y) ||> f = (x, f y)*} |
435 ML{*fun (x, y) ||> f = (x, f y)*} |
435 |
436 |
436 text {* |
437 text {* |
437 With the combinator @{ML "|->"} you can re-combine the elements from a pair. |
438 With the combinator @{ML [index] "|->"} you can re-combine the elements from a pair. |
438 This combinator is defined as |
439 This combinator is defined as |
439 *} |
440 *} |
440 |
441 |
441 ML{*fun (x, y) |-> f = f x y*} |
442 ML{*fun (x, y) |-> f = f x y*} |
442 |
443 |
448 ML{*fun double x = |
449 ML{*fun double x = |
449 x |> (fn x => (x, x)) |
450 x |> (fn x => (x, x)) |
450 |-> (fn x => fn y => x + y)*} |
451 |-> (fn x => fn y => x + y)*} |
451 |
452 |
452 text {* |
453 text {* |
453 The combinator @{ML ||>>} plays a central rôle whenever your task is to update a |
454 The combinator @{ML [index] ||>>} plays a central rôle whenever your task is to update a |
454 theory and the update also produces a side-result (for example a theorem). Functions |
455 theory and the update also produces a side-result (for example a theorem). Functions |
455 for such tasks return a pair whose second component is the theory and the fist |
456 for such tasks return a pair whose second component is the theory and the fist |
456 component is the side-result. Using @{ML ||>>}, you can do conveniently the update |
457 component is the side-result. Using @{ML [index] ||>>}, you can do conveniently the update |
457 and also accumulate the side-results. Considder the following simple function. |
458 and also accumulate the side-results. Considder the following simple function. |
458 *} |
459 *} |
459 |
460 |
460 ML %linenosgray{*fun acc_incs x = |
461 ML %linenosgray{*fun acc_incs x = |
461 x |> (fn x => ("", x)) |
462 x |> (fn x => ("", x)) |
463 ||>> (fn x => (x, x + 1)) |
464 ||>> (fn x => (x, x + 1)) |
464 ||>> (fn x => (x, x + 1))*} |
465 ||>> (fn x => (x, x + 1))*} |
465 |
466 |
466 text {* |
467 text {* |
467 The purpose of Line 2 is to just pair up the argument with a dummy value (since |
468 The purpose of Line 2 is to just pair up the argument with a dummy value (since |
468 @{ML "||>>"} operates on pairs). Each of the next three lines just increment |
469 @{ML [index] "||>>"} operates on pairs). Each of the next three lines just increment |
469 the value by one, but also nest the intrermediate results to the left. For example |
470 the value by one, but also nest the intrermediate results to the left. For example |
470 |
471 |
471 @{ML_response [display,gray] |
472 @{ML_response [display,gray] |
472 "acc_incs 1" |
473 "acc_incs 1" |
473 "((((\"\", 1), 2), 3), 4)"} |
474 "((((\"\", 1), 2), 3), 4)"} |
480 |
481 |
481 (FIXME: maybe give a ``real world'' example) |
482 (FIXME: maybe give a ``real world'' example) |
482 *} |
483 *} |
483 |
484 |
484 text {* |
485 text {* |
485 Recall that @{ML "|>"} is the reverse function application. Recall also that |
486 Recall that @{ML [index] "|>"} is the reverse function application. Recall also that |
486 the related |
487 the related |
487 reverse function composition is @{ML "#>"}. In fact all the combinators @{ML "|->"}, |
488 reverse function composition is @{ML [index] "#>"}. In fact all the combinators |
488 @{ML "|>>"} , @{ML "||>"} and @{ML "||>>"} described above have related combinators for |
489 @{ML [index] "|->"}, @{ML [index] "|>>"} , @{ML [index] "||>"} and @{ML [index] |
489 function composition, namely @{ML "#->"}, @{ML "#>>"}, @{ML "##>"} and @{ML "##>>"}. |
490 "||>>"} described above have related combinators for |
490 Using @{ML "#->"}, for example, the function @{text double} can also be written as: |
491 function composition, namely @{ML [index] "#->"}, @{ML [index] "#>>"}, |
|
492 @{ML [index] "##>"} and @{ML [index] "##>>"}. |
|
493 Using @{ML [index] "#->"}, for example, the function @{text double} can also be written as: |
491 *} |
494 *} |
492 |
495 |
493 ML{*val double = |
496 ML{*val double = |
494 (fn x => (x, x)) |
497 (fn x => (x, x)) |
495 #-> (fn x => fn y => x + y)*} |
498 #-> (fn x => fn y => x + y)*} |
522 @{ML_response [display,gray] "Context.theory_name @{theory}" "\"FirstSteps\""} |
525 @{ML_response [display,gray] "Context.theory_name @{theory}" "\"FirstSteps\""} |
523 |
526 |
524 where @{text "@{theory}"} is an antiquotation that is substituted with the |
527 where @{text "@{theory}"} is an antiquotation that is substituted with the |
525 current theory (remember that we assumed we are inside the theory |
528 current theory (remember that we assumed we are inside the theory |
526 @{text FirstSteps}). The name of this theory can be extracted using |
529 @{text FirstSteps}). The name of this theory can be extracted using |
527 the function @{ML "Context.theory_name"}. |
530 the function @{ML [index] theory_name in Context}. |
528 |
531 |
529 Note, however, that antiquotations are statically linked, that is their value is |
532 Note, however, that antiquotations are statically linked, that is their value is |
530 determined at ``compile-time'', not ``run-time''. For example the function |
533 determined at ``compile-time'', not ``run-time''. For example the function |
531 *} |
534 *} |
532 |
535 |
564 in |
567 in |
565 map #1 simps |
568 map #1 simps |
566 end*} |
569 end*} |
567 |
570 |
568 text {* |
571 text {* |
569 The function @{ML dest_ss in MetaSimplifier} returns a record containing all |
572 The function @{ML [index] dest_ss in MetaSimplifier} returns a record containing all |
570 information stored in the simpset, but we are only interested in the names of the |
573 information stored in the simpset, but we are only interested in the names of the |
571 simp-rules. Now you can feed in the current simpset into this function. |
574 simp-rules. Now you can feed in the current simpset into this function. |
572 The current simpset can be referred to using the antiquotation @{text "@{simpset}"}. |
575 The current simpset can be referred to using the antiquotation @{text "@{simpset}"}. |
573 |
576 |
574 @{ML_response_fake [display,gray] |
577 @{ML_response_fake [display,gray] |
585 |
588 |
586 @{ML_response [display,gray] |
589 @{ML_response [display,gray] |
587 "@{binding \"name\"}" |
590 "@{binding \"name\"}" |
588 "name"} |
591 "name"} |
589 |
592 |
590 An example where a binding is needed is the function @{ML define in |
593 An example where a binding is needed is the function @{ML [index] define in |
591 LocalTheory}. This function is below used to define the constant @{term |
594 LocalTheory}. This function is below used to define the constant @{term |
592 "TrueConj"} as the conjunction |
595 "TrueConj"} as the conjunction |
593 @{term "True \<and> True"}. |
596 @{term "True \<and> True"}. |
594 *} |
597 *} |
595 |
598 |
637 "@{term \"(a::nat) + b = c\"}" |
640 "@{term \"(a::nat) + b = c\"}" |
638 "Const (\"op =\", \<dots>) $ |
641 "Const (\"op =\", \<dots>) $ |
639 (Const (\"HOL.plus_class.plus\", \<dots>) $ \<dots> $ \<dots>) $ \<dots>"} |
642 (Const (\"HOL.plus_class.plus\", \<dots>) $ \<dots> $ \<dots>) $ \<dots>"} |
640 |
643 |
641 will show the term @{term "(a::nat) + b = c"}, but printed using the internal |
644 will show the term @{term "(a::nat) + b = c"}, but printed using the internal |
642 representation corresponding to the datatype @{ML_type "term"} defined as follows: |
645 representation corresponding to the datatype @{ML_type [index] "term"} defined as follows: |
643 *} |
646 *} |
644 |
647 |
645 ML_val %linenosgray{*datatype term = |
648 ML_val %linenosgray{*datatype term = |
646 Const of string * typ |
649 Const of string * typ |
647 | Free of string * typ |
650 | Free of string * typ |
827 Abs (\"x\", \<dots>, |
830 Abs (\"x\", \<dots>, |
828 Const \<dots> $ (Const \<dots> $ (Free (\"P\",\<dots>) $ \<dots>)) $ |
831 Const \<dots> $ (Const \<dots> $ (Free (\"P\",\<dots>) $ \<dots>)) $ |
829 (Const \<dots> $ (Free (\"Q\",\<dots>) $ \<dots>)))"} |
832 (Const \<dots> $ (Free (\"Q\",\<dots>) $ \<dots>)))"} |
830 |
833 |
831 There are a number of handy functions that are frequently used for |
834 There are a number of handy functions that are frequently used for |
832 constructing terms. One is the function @{ML list_comb}, which takes a term |
835 constructing terms. One is the function @{ML [index] list_comb}, which takes a term |
833 and a list of terms as arguments, and produces as output the term |
836 and a list of terms as arguments, and produces as output the term |
834 list applied to the term. For example |
837 list applied to the term. For example |
835 |
838 |
836 @{ML_response_fake [display,gray] |
839 @{ML_response_fake [display,gray] |
837 "list_comb (@{term \"P::nat\"}, [@{term \"True\"}, @{term \"False\"}])" |
840 "list_comb (@{term \"P::nat\"}, [@{term \"True\"}, @{term \"False\"}])" |
838 "Free (\"P\", \"nat\") $ Const (\"True\", \"bool\") $ Const (\"False\", \"bool\")"} |
841 "Free (\"P\", \"nat\") $ Const (\"True\", \"bool\") $ Const (\"False\", \"bool\")"} |
839 |
842 |
840 Another handy function is @{ML lambda}, which abstracts a variable |
843 Another handy function is @{ML [index] lambda}, which abstracts a variable |
841 in a term. For example |
844 in a term. For example |
842 |
845 |
843 @{ML_response_fake [display,gray] |
846 @{ML_response_fake [display,gray] |
844 "lambda @{term \"x::nat\"} @{term \"(P::nat\<Rightarrow>bool) x\"}" |
847 "lambda @{term \"x::nat\"} @{term \"(P::nat\<Rightarrow>bool) x\"}" |
845 "Abs (\"x\", \"nat\", Free (\"P\", \"bool \<Rightarrow> bool\") $ Bound 0)"} |
848 "Abs (\"x\", \"nat\", Free (\"P\", \"bool \<Rightarrow> bool\") $ Bound 0)"} |
858 then the variable @{text "Free (\"x\", \"bool\")"} is \emph{not} abstracted. |
861 then the variable @{text "Free (\"x\", \"bool\")"} is \emph{not} abstracted. |
859 This is a fundamental principle |
862 This is a fundamental principle |
860 of Church-style typing, where variables with the same name still differ, if they |
863 of Church-style typing, where variables with the same name still differ, if they |
861 have different type. |
864 have different type. |
862 |
865 |
863 There is also the function @{ML subst_free} with which terms can |
866 There is also the function @{ML [index] subst_free} with which terms can |
864 be replaced by other terms. For example below, we will replace in |
867 be replaced by other terms. For example below, we will replace in |
865 @{term "(f::nat\<Rightarrow>nat\<Rightarrow>nat) 0 x"} |
868 @{term "(f::nat\<Rightarrow>nat\<Rightarrow>nat) 0 x"} |
866 the subterm @{term "(f::nat\<Rightarrow>nat\<Rightarrow>nat) 0"} by @{term y}, and @{term x} by @{term True}. |
869 the subterm @{term "(f::nat\<Rightarrow>nat\<Rightarrow>nat) 0"} by @{term y}, and @{term x} by @{term True}. |
867 |
870 |
868 @{ML_response_fake [display,gray] |
871 @{ML_response_fake [display,gray] |
878 "subst_free [(@{term \"(\<lambda>y::nat. y)\"}, @{term \"x::nat\"})] |
881 "subst_free [(@{term \"(\<lambda>y::nat. y)\"}, @{term \"x::nat\"})] |
879 @{term \"(\<lambda>x::nat. x)\"}" |
882 @{term \"(\<lambda>x::nat. x)\"}" |
880 "Free (\"x\", \"nat\")"} |
883 "Free (\"x\", \"nat\")"} |
881 |
884 |
882 There are many convenient functions that construct specific HOL-terms. For |
885 There are many convenient functions that construct specific HOL-terms. For |
883 example @{ML "HOLogic.mk_eq"} constructs an equality out of two terms. |
886 example @{ML [index] mk_eq in HOLogic} constructs an equality out of two terms. |
884 The types needed in this equality are calculated from the type of the |
887 The types needed in this equality are calculated from the type of the |
885 arguments. For example |
888 arguments. For example |
886 |
889 |
887 @{ML_response_fake [gray,display] |
890 @{ML_response_fake [gray,display] |
888 "writeln (Syntax.string_of_term @{context} |
891 "writeln (Syntax.string_of_term @{context} |
1004 "@{type_name \"list\"}" "\"List.list\""} |
1007 "@{type_name \"list\"}" "\"List.list\""} |
1005 |
1008 |
1006 (FIXME: Explain the following better.) |
1009 (FIXME: Explain the following better.) |
1007 |
1010 |
1008 Occasionally you have to calculate what the ``base'' name of a given |
1011 Occasionally you have to calculate what the ``base'' name of a given |
1009 constant is. For this you can use the function @{ML Sign.extern_const} or |
1012 constant is. For this you can use the function @{ML [index] extern_const in Sign} or |
1010 @{ML Long_Name.base_name}. For example: |
1013 @{ML base_name in Long_Name}. For example: |
1011 |
1014 |
1012 @{ML_response [display,gray] "Sign.extern_const @{theory} \"List.list.Nil\"" "\"Nil\""} |
1015 @{ML_response [display,gray] "Sign.extern_const @{theory} \"List.list.Nil\"" "\"Nil\""} |
1013 |
1016 |
1014 The difference between both functions is that @{ML extern_const in Sign} returns |
1017 The difference between both functions is that @{ML extern_const in Sign} returns |
1015 the smallest name that is still unique, whereas @{ML base_name in Long_Name} always |
1018 the smallest name that is still unique, whereas @{ML base_name in Long_Name} always |
1031 |
1034 |
1032 *} |
1035 *} |
1033 |
1036 |
1034 ML{*fun make_fun_type ty1 ty2 = Type ("fun", [ty1, ty2]) *} |
1037 ML{*fun make_fun_type ty1 ty2 = Type ("fun", [ty1, ty2]) *} |
1035 |
1038 |
1036 text {* This can be equally written with the combinator @{ML "-->"} as: *} |
1039 text {* This can be equally written with the combinator @{ML [index] "-->"} as: *} |
1037 |
1040 |
1038 ML{*fun make_fun_type ty1 ty2 = ty1 --> ty2 *} |
1041 ML{*fun make_fun_type ty1 ty2 = ty1 --> ty2 *} |
1039 |
1042 |
1040 text {* |
1043 text {* |
1041 If you want to construct a function type with more than one argument |
1044 If you want to construct a function type with more than one argument |
1042 type, then you can use @{ML "--->"}. |
1045 type, then you can use @{ML [index] "--->"}. |
1043 *} |
1046 *} |
1044 |
1047 |
1045 ML{*fun make_fun_types tys ty = tys ---> ty *} |
1048 ML{*fun make_fun_types tys ty = tys ---> ty *} |
1046 |
1049 |
1047 text {* |
1050 text {* |
1048 A handy function for manipulating terms is @{ML map_types}: it takes a |
1051 A handy function for manipulating terms is @{ML [index] map_types}: it takes a |
1049 function and applies it to every type in a term. You can, for example, |
1052 function and applies it to every type in a term. You can, for example, |
1050 change every @{typ nat} in a term into an @{typ int} using the function: |
1053 change every @{typ nat} in a term into an @{typ int} using the function: |
1051 *} |
1054 *} |
1052 |
1055 |
1053 ML{*fun nat_to_int ty = |
1056 ML{*fun nat_to_int ty = |
1063 "map_types nat_to_int @{term \"a = (1::nat)\"}" |
1066 "map_types nat_to_int @{term \"a = (1::nat)\"}" |
1064 "Const (\"op =\", \"int \<Rightarrow> int \<Rightarrow> bool\") |
1067 "Const (\"op =\", \"int \<Rightarrow> int \<Rightarrow> bool\") |
1065 $ Free (\"a\", \"int\") $ Const (\"HOL.one_class.one\", \"int\")"} |
1068 $ Free (\"a\", \"int\") $ Const (\"HOL.one_class.one\", \"int\")"} |
1066 |
1069 |
1067 If you want to obtain the list of free type-variables of a term, you |
1070 If you want to obtain the list of free type-variables of a term, you |
1068 can use the function @{ML Term.add_tfrees} (similarly @{ML Term.add_tvars} |
1071 can use the function @{ML [index] add_tfrees in Term} |
1069 for the schematic type-variables). One would expect that such functions |
1072 (similarly @{ML [index] add_tvars in Term} for the schematic type-variables). |
|
1073 One would expect that such functions |
1070 take a term as input and return a list of types. But their type is actually |
1074 take a term as input and return a list of types. But their type is actually |
1071 |
1075 |
1072 @{text[display] "Term.term -> (string * Term.sort) list -> (string * Term.sort) list"} |
1076 @{text[display] "Term.term -> (string * Term.sort) list -> (string * Term.sort) list"} |
1073 |
1077 |
1074 that is they take, besides a term, also a list of type-variables as input. |
1078 that is they take, besides a term, also a list of type-variables as input. |
1077 |
1081 |
1078 @{ML_response [gray,display] |
1082 @{ML_response [gray,display] |
1079 "Term.add_tfrees @{term \"(a,b)\"} []" |
1083 "Term.add_tfrees @{term \"(a,b)\"} []" |
1080 "[(\"'b\", [\"HOL.type\"]), (\"'a\", [\"HOL.type\"])]"} |
1084 "[(\"'b\", [\"HOL.type\"]), (\"'a\", [\"HOL.type\"])]"} |
1081 |
1085 |
1082 The reason for this definition is that @{ML Term.add_tfrees} can |
1086 The reason for this definition is that @{ML add_tfrees in Term} can |
1083 be easily folded over a list of terms. Similarly for all functions |
1087 be easily folded over a list of terms. Similarly for all functions |
1084 named @{text "add_"}some\_name in @{ML_file "Pure/term.ML"}. |
1088 named @{text "add_"}some\_name in @{ML_file "Pure/term.ML"}. |
1085 |
1089 |
1086 *} |
1090 *} |
1087 |
1091 |
1091 text {* |
1095 text {* |
1092 |
1096 |
1093 You can freely construct and manipulate @{ML_type "term"}s and @{ML_type |
1097 You can freely construct and manipulate @{ML_type "term"}s and @{ML_type |
1094 typ}es, since they are just arbitrary unchecked trees. However, you |
1098 typ}es, since they are just arbitrary unchecked trees. However, you |
1095 eventually want to see if a term is well-formed, or type-checks, relative to |
1099 eventually want to see if a term is well-formed, or type-checks, relative to |
1096 a theory. Type-checking is done via the function @{ML cterm_of}, which |
1100 a theory. Type-checking is done via the function @{ML [index] cterm_of}, which |
1097 converts a @{ML_type term} into a @{ML_type cterm}, a \emph{certified} |
1101 converts a @{ML_type [index] term} into a @{ML_type [index] cterm}, a \emph{certified} |
1098 term. Unlike @{ML_type term}s, which are just trees, @{ML_type "cterm"}s are |
1102 term. Unlike @{ML_type term}s, which are just trees, @{ML_type "cterm"}s are |
1099 abstract objects that are guaranteed to be type-correct, and they can only |
1103 abstract objects that are guaranteed to be type-correct, and they can only |
1100 be constructed via ``official interfaces''. |
1104 be constructed via ``official interfaces''. |
1101 |
1105 |
1102 |
1106 |
1151 \end{exercise} |
1155 \end{exercise} |
1152 |
1156 |
1153 Remember Isabelle follows the Church-style typing for terms, i.e., a term contains |
1157 Remember Isabelle follows the Church-style typing for terms, i.e., a term contains |
1154 enough typing information (constants, free variables and abstractions all have typing |
1158 enough typing information (constants, free variables and abstractions all have typing |
1155 information) so that it is always clear what the type of a term is. |
1159 information) so that it is always clear what the type of a term is. |
1156 Given a well-typed term, the function @{ML type_of} returns the |
1160 Given a well-typed term, the function @{ML [index] type_of} returns the |
1157 type of a term. Consider for example: |
1161 type of a term. Consider for example: |
1158 |
1162 |
1159 @{ML_response [display,gray] |
1163 @{ML_response [display,gray] |
1160 "type_of (@{term \"f::nat \<Rightarrow> bool\"} $ @{term \"x::nat\"})" "bool"} |
1164 "type_of (@{term \"f::nat \<Rightarrow> bool\"} $ @{term \"x::nat\"})" "bool"} |
1161 |
1165 |
1166 @{ML_response_fake [display,gray] |
1170 @{ML_response_fake [display,gray] |
1167 "type_of (@{term \"f::nat \<Rightarrow> bool\"} $ @{term \"x::int\"})" |
1171 "type_of (@{term \"f::nat \<Rightarrow> bool\"} $ @{term \"x::int\"})" |
1168 "*** Exception- TYPE (\"type_of: type mismatch in application\" \<dots>"} |
1172 "*** Exception- TYPE (\"type_of: type mismatch in application\" \<dots>"} |
1169 |
1173 |
1170 Since the complete traversal might sometimes be too costly and |
1174 Since the complete traversal might sometimes be too costly and |
1171 not necessary, there is the function @{ML fastype_of}, which |
1175 not necessary, there is the function @{ML [index] fastype_of}, which |
1172 also returns the type of a term. |
1176 also returns the type of a term. |
1173 |
1177 |
1174 @{ML_response [display,gray] |
1178 @{ML_response [display,gray] |
1175 "fastype_of (@{term \"f::nat \<Rightarrow> bool\"} $ @{term \"x::nat\"})" "bool"} |
1179 "fastype_of (@{term \"f::nat \<Rightarrow> bool\"} $ @{term \"x::nat\"})" "bool"} |
1176 |
1180 |
1183 where no error is detected. |
1187 where no error is detected. |
1184 |
1188 |
1185 Sometimes it is a bit inconvenient to construct a term with |
1189 Sometimes it is a bit inconvenient to construct a term with |
1186 complete typing annotations, especially in cases where the typing |
1190 complete typing annotations, especially in cases where the typing |
1187 information is redundant. A short-cut is to use the ``place-holder'' |
1191 information is redundant. A short-cut is to use the ``place-holder'' |
1188 type @{ML "dummyT"} and then let type-inference figure out the |
1192 type @{ML [index] dummyT} and then let type-inference figure out the |
1189 complete type. An example is as follows: |
1193 complete type. An example is as follows: |
1190 |
1194 |
1191 @{ML_response_fake [display,gray] |
1195 @{ML_response_fake [display,gray] |
1192 "let |
1196 "let |
1193 val c = Const (@{const_name \"plus\"}, dummyT) |
1197 val c = Const (@{const_name \"plus\"}, dummyT) |
1273 For the functions @{text "assume"}, @{text "forall_elim"} etc |
1277 For the functions @{text "assume"}, @{text "forall_elim"} etc |
1274 see \isccite{sec:thms}. The basic functions for theorems are defined in |
1278 see \isccite{sec:thms}. The basic functions for theorems are defined in |
1275 @{ML_file "Pure/thm.ML"}. |
1279 @{ML_file "Pure/thm.ML"}. |
1276 \end{readmore} |
1280 \end{readmore} |
1277 |
1281 |
1278 (FIXME: handy functions working on theorems, like @{ML ObjectLogic.rulify} and so on) |
1282 (FIXME: handy functions working on theorems, like @{ML [index] rulify in ObjectLogic} and so on) |
1279 |
1283 |
1280 (FIXME: how to add case-names to goal states - maybe in the |
1284 (FIXME: how to add case-names to goal states - maybe in the |
1281 next section) |
1285 next section) |
1282 *} |
1286 *} |
1283 |
1287 |
1290 @{ML_type "theory -> theory"}: the input theory is the current theory and the |
1294 @{ML_type "theory -> theory"}: the input theory is the current theory and the |
1291 output the theory where the theory attribute has been stored. |
1295 output the theory where the theory attribute has been stored. |
1292 |
1296 |
1293 This is a fundamental principle in Isabelle. A similar situation occurs |
1297 This is a fundamental principle in Isabelle. A similar situation occurs |
1294 for example with declaring constants. The function that declares a |
1298 for example with declaring constants. The function that declares a |
1295 constant on the ML-level is @{ML Sign.add_consts_i}. |
1299 constant on the ML-level is @{ML [index] add_consts_i in Sign}. |
1296 If you write\footnote{Recall that ML-code needs to be |
1300 If you write\footnote{Recall that ML-code needs to be |
1297 enclosed in \isacommand{ML}~@{text "\<verbopen> \<dots> \<verbclose>"}.} |
1301 enclosed in \isacommand{ML}~@{text "\<verbopen> \<dots> \<verbclose>"}.} |
1298 *} |
1302 *} |
1299 |
1303 |
1300 ML{*Sign.add_consts_i [(@{binding "BAR"}, @{typ "nat"}, NoSyn)] @{theory} *} |
1304 ML{*Sign.add_consts_i [(@{binding "BAR"}, @{typ "nat"}, NoSyn)] @{theory} *} |
1368 *} |
1372 *} |
1369 |
1373 |
1370 ML{*val my_symmetric = Thm.rule_attribute (fn _ => fn thm => thm RS @{thm sym})*} |
1374 ML{*val my_symmetric = Thm.rule_attribute (fn _ => fn thm => thm RS @{thm sym})*} |
1371 |
1375 |
1372 text {* |
1376 text {* |
1373 where the function @{ML "Thm.rule_attribute"} expects a function taking a |
1377 where the function @{ML [index] rule_attribute in Thm} expects a function taking a |
1374 context (which we ignore in the code above) and a theorem (@{text thm}), and |
1378 context (which we ignore in the code above) and a theorem (@{text thm}), and |
1375 returns another theorem (namely @{text thm} resolved with the theorem |
1379 returns another theorem (namely @{text thm} resolved with the theorem |
1376 @{thm [source] sym}: @{thm sym[no_vars]}).\footnote{The function @{ML RS} is explained |
1380 @{thm [source] sym}: @{thm sym[no_vars]}).\footnote{The function @{ML [index] RS} |
1377 in Section~\ref{sec:simpletacs}.} The function |
1381 is explained in Section~\ref{sec:simpletacs}.} The function |
1378 @{ML "Thm.rule_attribute"} then returns |
1382 @{ML rule_attribute in Thm} then returns an attribute. |
1379 an attribute. |
|
1380 |
1383 |
1381 Before we can use the attribute, we need to set it up. This can be done |
1384 Before we can use the attribute, we need to set it up. This can be done |
1382 using the Isabelle command \isacommand{attribute\_setup} as follows: |
1385 using the Isabelle command \isacommand{attribute\_setup} as follows: |
1383 *} |
1386 *} |
1384 |
1387 |
1409 \begin{isabelle} |
1412 \begin{isabelle} |
1410 \isacommand{thm}~@{text "test[my_sym]"}\\ |
1413 \isacommand{thm}~@{text "test[my_sym]"}\\ |
1411 @{text "> "}~@{thm test[my_sym]} |
1414 @{text "> "}~@{thm test[my_sym]} |
1412 \end{isabelle} |
1415 \end{isabelle} |
1413 |
1416 |
1414 An alternative for setting up an attribute is the function @{ML Attrib.setup}. |
1417 An alternative for setting up an attribute is the function @{ML [index] setup in Attrib}. |
1415 So instead of using \isacommand{attribute\_setup}, you can also set up the |
1418 So instead of using \isacommand{attribute\_setup}, you can also set up the |
1416 attribute as follows: |
1419 attribute as follows: |
1417 *} |
1420 *} |
1418 |
1421 |
1419 ML{*Attrib.setup @{binding "my_sym"} (Scan.succeed my_symmetric) |
1422 ML{*Attrib.setup @{binding "my_sym"} (Scan.succeed my_symmetric) |
1432 ML{*fun MY_THEN thms = |
1435 ML{*fun MY_THEN thms = |
1433 Thm.rule_attribute (fn _ => fn thm => foldl ((op RS) o swap) thm thms)*} |
1436 Thm.rule_attribute (fn _ => fn thm => foldl ((op RS) o swap) thm thms)*} |
1434 |
1437 |
1435 text {* |
1438 text {* |
1436 where @{ML swap} swaps the components of a pair. The setup of this theorem |
1439 where @{ML swap} swaps the components of a pair. The setup of this theorem |
1437 attribute uses the parser @{ML Attrib.thms}, which parses a list of |
1440 attribute uses the parser @{ML thms in Attrib}, which parses a list of |
1438 theorems. |
1441 theorems. |
1439 *} |
1442 *} |
1440 |
1443 |
1441 attribute_setup %gray MY_THEN = {* Attrib.thms >> MY_THEN *} |
1444 attribute_setup %gray MY_THEN = {* Attrib.thms >> MY_THEN *} |
1442 "resolving the list of theorems with the proved theorem" |
1445 "resolving the list of theorems with the proved theorem" |
1474 \end{isabelle} |
1477 \end{isabelle} |
1475 |
1478 |
1476 you get an exception indicating that the theorem @{thm [source] sym} |
1479 you get an exception indicating that the theorem @{thm [source] sym} |
1477 does not resolve with meta-equations. |
1480 does not resolve with meta-equations. |
1478 |
1481 |
1479 The purpose of @{ML Thm.rule_attribute} is to directly manipulate theorems. |
1482 The purpose of @{ML [index] rule_attribute in Thm} is to directly manipulate theorems. |
1480 Another usage of theorem attributes is to add and delete theorems from stored data. |
1483 Another usage of theorem attributes is to add and delete theorems from stored data. |
1481 For example the theorem attribute @{text "[simp]"} adds or deletes a theorem from the |
1484 For example the theorem attribute @{text "[simp]"} adds or deletes a theorem from the |
1482 current simpset. For these applications, you can use @{ML Thm.declaration_attribute}. |
1485 current simpset. For these applications, you can use @{ML [index] declaration_attribute in Thm}. |
1483 To illustrate this function, let us introduce a reference containing a list |
1486 To illustrate this function, let us introduce a reference containing a list |
1484 of theorems. |
1487 of theorems. |
1485 *} |
1488 *} |
1486 |
1489 |
1487 ML{*val my_thms = ref ([] : thm list)*} |
1490 ML{*val my_thms = ref ([] : thm list)*} |
1504 (my_thms := Thm.del_thm thm (!my_thms); ctxt)*} |
1507 (my_thms := Thm.del_thm thm (!my_thms); ctxt)*} |
1505 |
1508 |
1506 text {* |
1509 text {* |
1507 These functions take a theorem and a context and, for what we are explaining |
1510 These functions take a theorem and a context and, for what we are explaining |
1508 here it is sufficient that they just return the context unchanged. They change |
1511 here it is sufficient that they just return the context unchanged. They change |
1509 however the reference @{ML my_thms}, whereby the function @{ML Thm.add_thm} |
1512 however the reference @{ML my_thms}, whereby the function |
1510 adds a theorem if it is not already included in the list, and @{ML |
1513 @{ML [index] add_thm in Thm} adds a theorem if it is not already included in |
1511 Thm.del_thm} deletes one (both functions use the predicate @{ML |
1514 the list, and @{ML [index] del_thm in Thm} deletes one (both functions use the |
1512 Thm.eq_thm_prop}, which compares theorems according to their proved |
1515 predicate @{ML [index] eq_thm_prop in Thm}, which compares theorems according to |
1513 propositions modulo alpha-equivalence). |
1516 their proved propositions modulo alpha-equivalence). |
1514 |
|
1515 |
1517 |
1516 You can turn functions @{ML my_thm_add} and @{ML my_thm_del} into |
1518 You can turn functions @{ML my_thm_add} and @{ML my_thm_del} into |
1517 attributes with the code |
1519 attributes with the code |
1518 *} |
1520 *} |
1519 |
1521 |
1526 |
1528 |
1527 attribute_setup %gray my_thms = {* Attrib.add_del my_add my_del *} |
1529 attribute_setup %gray my_thms = {* Attrib.add_del my_add my_del *} |
1528 "maintaining a list of my_thms - rough test only!" |
1530 "maintaining a list of my_thms - rough test only!" |
1529 |
1531 |
1530 text {* |
1532 text {* |
1531 The parser @{ML Attrib.add_del} is a pre-defined parser for |
1533 The parser @{ML [index] add_del in Attrib} is a pre-defined parser for |
1532 adding and deleting lemmas. Now if you prove the next lemma |
1534 adding and deleting lemmas. Now if you prove the next lemma |
1533 and attach to it the attribute @{text "[my_thms]"} |
1535 and attach to it the attribute @{text "[my_thms]"} |
1534 *} |
1536 *} |
1535 |
1537 |
1536 lemma trueI_2[my_thms]: "True" by simp |
1538 lemma trueI_2[my_thms]: "True" by simp |
1554 @{ML_response_fake [display,gray] |
1556 @{ML_response_fake [display,gray] |
1555 "!my_thms" |
1557 "!my_thms" |
1556 "[\"True\", \"Suc (Suc 0) = 2\"]"} |
1558 "[\"True\", \"Suc (Suc 0) = 2\"]"} |
1557 |
1559 |
1558 The theorem @{thm [source] trueI_2} only appears once, since the |
1560 The theorem @{thm [source] trueI_2} only appears once, since the |
1559 function @{ML Thm.add_thm} tests for duplicates, before extending |
1561 function @{ML [index] add_thm in Thm} tests for duplicates, before extending |
1560 the list. Deletion from the list works as follows: |
1562 the list. Deletion from the list works as follows: |
1561 *} |
1563 *} |
1562 |
1564 |
1563 declare test[my_thms del] |
1565 declare test[my_thms del] |
1564 |
1566 |
1566 |
1568 |
1567 @{ML_response_fake [display,gray] |
1569 @{ML_response_fake [display,gray] |
1568 "!my_thms" |
1570 "!my_thms" |
1569 "[\"True\"]"} |
1571 "[\"True\"]"} |
1570 |
1572 |
1571 We used in this example two functions declared as @{ML Thm.declaration_attribute}, |
1573 We used in this example two functions declared as @{ML [index] declaration_attribute in Thm}, |
1572 but there can be any number of them. We just have to change the parser for reading |
1574 but there can be any number of them. We just have to change the parser for reading |
1573 the arguments accordingly. |
1575 the arguments accordingly. |
1574 |
1576 |
1575 However, as said at the beginning of this example, using references for storing theorems is |
1577 However, as said at the beginning of this example, using references for storing theorems is |
1576 \emph{not} the received way of doing such things. The received way is to |
1578 \emph{not} the received way of doing such things. The received way is to |
1630 |
1632 |
1631 With theorem attribute @{text my_thms2} you can also nicely see why it |
1633 With theorem attribute @{text my_thms2} you can also nicely see why it |
1632 is important to |
1634 is important to |
1633 store data in a ``data slot'' and \emph{not} in a reference. Backtrack |
1635 store data in a ``data slot'' and \emph{not} in a reference. Backtrack |
1634 to the point just before the lemma @{thm [source] three} was proved and |
1636 to the point just before the lemma @{thm [source] three} was proved and |
1635 check the the content of @{ML_struct "MyThmsData"}: it should be empty. |
1637 check the the content of @{ML_struct MyThmsData}: it should be empty. |
1636 The addition has been properly retracted. Now consider the proof: |
1638 The addition has been properly retracted. Now consider the proof: |
1637 *} |
1639 *} |
1638 |
1640 |
1639 lemma four[my_thms]: "4 = Suc (Suc (Suc (Suc 0)))" by simp |
1641 lemma four[my_thms]: "4 = Suc (Suc (Suc (Suc 0)))" by simp |
1640 |
1642 |
1797 ML {* LocalTheory.set_group *} |
1799 ML {* LocalTheory.set_group *} |
1798 *) |
1800 *) |
1799 |
1801 |
1800 section {* Storing Theorems\label{sec:storing} (TBD) *} |
1802 section {* Storing Theorems\label{sec:storing} (TBD) *} |
1801 |
1803 |
1802 text {* @{ML PureThy.add_thms_dynamic} *} |
1804 text {* @{ML [index] add_thms_dynamic in PureThy} *} |
1803 |
1805 |
1804 local_setup {* |
1806 local_setup {* |
1805 LocalTheory.note Thm.theoremK |
1807 LocalTheory.note Thm.theoremK |
1806 ((@{binding "allI_alt"}, []), [@{thm allI}]) #> snd *} |
1808 ((@{binding "allI_alt"}, []), [@{thm allI}]) #> snd *} |
1807 |
1809 |
1843 sophisticated, Isabelle includes an infrastructure for properly formatting text. |
1845 sophisticated, Isabelle includes an infrastructure for properly formatting text. |
1844 This infrastructure is loosely based on a paper by Oppen~\cite{Oppen80}. Most of |
1846 This infrastructure is loosely based on a paper by Oppen~\cite{Oppen80}. Most of |
1845 its functions do not operate on @{ML_type string}s, but on instances of the |
1847 its functions do not operate on @{ML_type string}s, but on instances of the |
1846 type: |
1848 type: |
1847 |
1849 |
1848 @{ML_type [display, gray] "Pretty.T"} |
1850 @{ML_type [display, gray, index] "Pretty.T"} |
1849 |
1851 |
1850 The function @{ML "Pretty.str"} transforms a (plain) string into such a pretty |
1852 The function @{ML str in Pretty} transforms a (plain) string into such a pretty |
1851 type. For example |
1853 type. For example |
1852 |
1854 |
1853 @{ML_response_fake [display,gray] |
1855 @{ML_response_fake [display,gray] |
1854 "Pretty.str \"test\"" "String (\"test\", 4)"} |
1856 "Pretty.str \"test\"" "String (\"test\", 4)"} |
1855 |
1857 |
1856 where the result indicates that we transformed a string with length 4. Once |
1858 where the result indicates that we transformed a string with length 4. Once |
1857 you have a pretty type, you can, for example, control where linebreaks may |
1859 you have a pretty type, you can, for example, control where linebreaks may |
1858 occur in case the text wraps over a line, or with how much indentation a |
1860 occur in case the text wraps over a line, or with how much indentation a |
1859 text should be printed. However, if you want to actually output the |
1861 text should be printed. However, if you want to actually output the |
1860 formatted text, you have to transform the pretty type back into a @{ML_type |
1862 formatted text, you have to transform the pretty type back into a @{ML_type |
1861 string}. This can be done with the function @{ML Pretty.string_of}. In what |
1863 string}. This can be done with the function @{ML [index] string_of in Pretty}. In what |
1862 follows we will use the following wrapper function for printing a pretty |
1864 follows we will use the following wrapper function for printing a pretty |
1863 type: |
1865 type: |
1864 *} |
1866 *} |
1865 |
1867 |
1866 ML{*fun pprint prt = writeln (Pretty.string_of prt)*} |
1868 ML{*fun pprint prt = writeln (Pretty.string_of prt)*} |
1901 aaaaaaar fooooooooooooooobaaaaaaaaaaaar fooooooooooooooobaaaaaaaaaaaar fo |
1903 aaaaaaar fooooooooooooooobaaaaaaaaaaaar fooooooooooooooobaaaaaaaaaaaar fo |
1902 oooooooooooooobaaaaaaaaaaaar"} |
1904 oooooooooooooobaaaaaaaaaaaar"} |
1903 |
1905 |
1904 However by using pretty types you have the ability to indicate a possible |
1906 However by using pretty types you have the ability to indicate a possible |
1905 linebreak for example at each space. You can achieve this with the function |
1907 linebreak for example at each space. You can achieve this with the function |
1906 @{ML Pretty.breaks}, which expects a list of pretty types and inserts a |
1908 @{ML [index] breaks in Pretty}, which expects a list of pretty types and inserts a |
1907 possible linebreak in between every two elements in this list. To print |
1909 possible linebreak in between every two elements in this list. To print |
1908 this list of pretty types as a single string, we concatenate them |
1910 this list of pretty types as a single string, we concatenate them |
1909 with the function @{ML Pretty.blk} as follows: |
1911 with the function @{ML [index] blk in Pretty} as follows: |
1910 |
1912 |
1911 |
1913 |
1912 @{ML_response_fake [display,gray] |
1914 @{ML_response_fake [display,gray] |
1913 "let |
1915 "let |
1914 val ptrs = map Pretty.str (space_explode \" \" test_str) |
1916 val ptrs = map Pretty.str (space_explode \" \" test_str) |
1919 fooooooooooooooobaaaaaaaaaaaar fooooooooooooooobaaaaaaaaaaaar |
1921 fooooooooooooooobaaaaaaaaaaaar fooooooooooooooobaaaaaaaaaaaar |
1920 fooooooooooooooobaaaaaaaaaaaar fooooooooooooooobaaaaaaaaaaaar |
1922 fooooooooooooooobaaaaaaaaaaaar fooooooooooooooobaaaaaaaaaaaar |
1921 fooooooooooooooobaaaaaaaaaaaar fooooooooooooooobaaaaaaaaaaaar"} |
1923 fooooooooooooooobaaaaaaaaaaaar fooooooooooooooobaaaaaaaaaaaar"} |
1922 |
1924 |
1923 Here the layout of @{ML test_str} is much more pleasing to the |
1925 Here the layout of @{ML test_str} is much more pleasing to the |
1924 eye. The @{ML "0"} in @{ML Pretty.blk} stands for no indentation |
1926 eye. The @{ML "0"} in @{ML [index] blk in Pretty} stands for no indentation |
1925 of the printed string. You can increase the indentation and obtain |
1927 of the printed string. You can increase the indentation and obtain |
1926 |
1928 |
1927 @{ML_response_fake [display,gray] |
1929 @{ML_response_fake [display,gray] |
1928 "let |
1930 "let |
1929 val ptrs = map Pretty.str (space_explode \" \" test_str) |
1931 val ptrs = map Pretty.str (space_explode \" \" test_str) |
1935 fooooooooooooooobaaaaaaaaaaaar fooooooooooooooobaaaaaaaaaaaar |
1937 fooooooooooooooobaaaaaaaaaaaar fooooooooooooooobaaaaaaaaaaaar |
1936 fooooooooooooooobaaaaaaaaaaaar fooooooooooooooobaaaaaaaaaaaar"} |
1938 fooooooooooooooobaaaaaaaaaaaar fooooooooooooooobaaaaaaaaaaaar"} |
1937 |
1939 |
1938 where starting from the second line the indent is 3. If you want |
1940 where starting from the second line the indent is 3. If you want |
1939 that every line starts with the same indent, you can use the |
1941 that every line starts with the same indent, you can use the |
1940 function @{ML Pretty.indent} as follows: |
1942 function @{ML [index] indent in Pretty} as follows: |
1941 |
1943 |
1942 @{ML_response_fake [display,gray] |
1944 @{ML_response_fake [display,gray] |
1943 "let |
1945 "let |
1944 val ptrs = map Pretty.str (space_explode \" \" test_str) |
1946 val ptrs = map Pretty.str (space_explode \" \" test_str) |
1945 in |
1947 in |
1950 fooooooooooooooobaaaaaaaaaaaar fooooooooooooooobaaaaaaaaaaaar |
1952 fooooooooooooooobaaaaaaaaaaaar fooooooooooooooobaaaaaaaaaaaar |
1951 fooooooooooooooobaaaaaaaaaaaar fooooooooooooooobaaaaaaaaaaaar"} |
1953 fooooooooooooooobaaaaaaaaaaaar fooooooooooooooobaaaaaaaaaaaar"} |
1952 |
1954 |
1953 If you want to print out a list of items separated by commas and |
1955 If you want to print out a list of items separated by commas and |
1954 have the linebreaks handled properly, you can use the function |
1956 have the linebreaks handled properly, you can use the function |
1955 @{ML Pretty.commas}. For example |
1957 @{ML [index] commas in Pretty}. For example |
1956 |
1958 |
1957 @{ML_response_fake [display,gray] |
1959 @{ML_response_fake [display,gray] |
1958 "let |
1960 "let |
1959 val ptrs = map (Pretty.str o string_of_int) (99998 upto 100020) |
1961 val ptrs = map (Pretty.str o string_of_int) (99998 upto 100020) |
1960 in |
1962 in |
1965 100016, 100017, 100018, 100019, 100020"} |
1967 100016, 100017, 100018, 100019, 100020"} |
1966 |
1968 |
1967 where @{ML upto} generates a list of integers. You can print this |
1969 where @{ML upto} generates a list of integers. You can print this |
1968 list out as an ``set'', that means enclosed inside @{text [quotes] "{"} and |
1970 list out as an ``set'', that means enclosed inside @{text [quotes] "{"} and |
1969 @{text [quotes] "}"}, and separated by commas using the function |
1971 @{text [quotes] "}"}, and separated by commas using the function |
1970 @{ML Pretty.enum}. For example |
1972 @{ML [index] enum in Pretty}. For example |
1971 *} |
1973 *} |
1972 |
1974 |
1973 text {* |
1975 text {* |
1974 |
1976 |
1975 @{ML_response_fake [display,gray] |
1977 @{ML_response_fake [display,gray] |
2036 end*} |
2038 end*} |
2037 |
2039 |
2038 text {* |
2040 text {* |
2039 In Line 3 we define a function that inserts according to spaces |
2041 In Line 3 we define a function that inserts according to spaces |
2040 possible linebreaks into an (English). In Lines 4 and 5 we pretty-print |
2042 possible linebreaks into an (English). In Lines 4 and 5 we pretty-print |
2041 the term and its type using the functions @{ML Syntax.pretty_term} and |
2043 the term and its type using the functions @{ML [index] pretty_term in Syntax} and |
2042 @{ML Syntax.pretty_typ}. We also use the function @{ML Pretty.quote} |
2044 @{ML [index] pretty_typ in Syntax}. We also use the function @{ML [index] quote in Pretty} |
2043 in order to enclose the term and type inside quotation marks. In Line |
2045 in order to enclose the term and type inside quotation marks. In Line |
2044 9 we add a period right after the type without the possibility of a |
2046 9 we add a period right after the type without the possibility of a |
2045 linebreak, because we do not want that a linebreak occurs there. |
2047 linebreak, because we do not want that a linebreak occurs there. |
2046 |
2048 |
2047 Now you can write |
2049 Now you can write |