192 |
192 |
193 ML {* Toplevel.program (fn () => innocent ()) *} |
193 ML {* Toplevel.program (fn () => innocent ()) *} |
194 *) |
194 *) |
195 |
195 |
196 text {* |
196 text {* |
197 Most often you want to inspect data of type @{ML_type term}, @{ML_type cterm} |
197 Most often you want to inspect data of Isabelle's most basic datastructures, |
198 or @{ML_type thm}. Isabelle contains elaborate pretty-printing functions for printing |
198 namely @{ML_type term}, @{ML_type cterm} or @{ML_type thm}. Isabelle |
199 them (see Section \ref{sec:pretty}), |
199 contains elaborate pretty-printing functions for printing them (see Section |
200 but for quick-and-dirty solutions they are far too unwieldy. One way to transform |
200 \ref{sec:pretty}), but for quick-and-dirty solutions they are far too |
201 a term into a string is to use the function @{ML [index] string_of_term in Syntax}. |
201 unwieldy. One way to transform a term into a string is to use the function |
|
202 @{ML [index] string_of_term in Syntax}. |
|
203 |
202 |
204 |
203 @{ML_response_fake [display,gray] |
205 @{ML_response_fake [display,gray] |
204 "Syntax.string_of_term @{context} @{term \"1::nat\"}" |
206 "Syntax.string_of_term @{context} @{term \"1::nat\"}" |
205 "\"\\^E\\^Fterm\\^E\\^E\\^Fconst\\^Fname=HOL.one_class.one\\^E1\\^E\\^F\\^E\\^E\\^F\\^E\""} |
207 "\"\\^E\\^Fterm\\^E\\^E\\^Fconst\\^Fname=HOL.one_class.one\\^E1\\^E\\^F\\^E\\^E\\^F\\^E\""} |
206 |
208 |
207 This produces a string with some additional information encoded in it. The string |
209 This produces a string with some additional information encoded in it. The string |
208 can be properly printed by using either the function @{ML [index] writeln} or |
210 can be properly printed by using either the function @{ML [index] writeln} or |
209 @{ML [index] tracing}. |
211 @{ML [index] tracing}: |
210 |
212 |
211 @{ML_response_fake [display,gray] |
213 @{ML_response_fake [display,gray] |
212 "writeln (Syntax.string_of_term @{context} @{term \"1::nat\"})" |
214 "writeln (Syntax.string_of_term @{context} @{term \"1::nat\"})" |
213 "\"1\""} |
215 "\"1\""} |
214 |
216 |
|
217 or |
|
218 |
|
219 @{ML_response_fake [display,gray] |
|
220 "tracing (Syntax.string_of_term @{context} @{term \"1::nat\"})" |
|
221 "\"1\""} |
|
222 |
215 A @{ML_type cterm} can be transformed into a string by the following function. |
223 A @{ML_type cterm} can be transformed into a string by the following function. |
216 *} |
224 *} |
217 |
225 |
218 ML{*fun string_of_cterm ctxt t = |
226 ML{*fun string_of_cterm ctxt t = |
219 Syntax.string_of_term ctxt (term_of t)*} |
227 Syntax.string_of_term ctxt (term_of t)*} |
220 |
228 |
221 text {* |
229 text {* |
222 In this example the function @{ML [index] term_of} extracts the @{ML_type term} from |
230 In this example the function @{ML [index] term_of} extracts the @{ML_type term} from |
223 a @{ML_type cterm}. If there are more than one @{ML_type cterm}s to be |
231 a @{ML_type cterm}. If there are more than one @{ML_type cterm}s to be |
224 printed, you can use the function @{ML [index] commas} to separate them. |
232 printed, you can use the function @{ML [index] commas} to separate them. |
225 *} |
233 *} |
226 |
234 |
227 ML{*fun string_of_cterms ctxt ts = |
235 ML{*fun string_of_cterms ctxt ts = |
228 commas (map (string_of_cterm ctxt) ts)*} |
236 commas (map (string_of_cterm ctxt) ts)*} |
229 |
237 |
230 text {* |
238 text {* |
231 The easiest way to get the string of a theorem is to transform it |
239 The easiest way to get the string of a theorem is to transform it |
232 into a @{ML_type cterm} using the function @{ML [index] crep_thm}. |
240 into a @{ML_type cterm} using the function @{ML [index] crep_thm}. |
233 *} |
241 *} |
243 "tracing (string_of_thm @{context} @{thm conjI})" |
251 "tracing (string_of_thm @{context} @{thm conjI})" |
244 "\<lbrakk>?P; ?Q\<rbrakk> \<Longrightarrow> ?P \<and> ?Q"} |
252 "\<lbrakk>?P; ?Q\<rbrakk> \<Longrightarrow> ?P \<and> ?Q"} |
245 |
253 |
246 In order to improve the readability of theorems we convert |
254 In order to improve the readability of theorems we convert |
247 these schematic variables into free variables using the |
255 these schematic variables into free variables using the |
248 function @{ML [index] import in Variable}. |
256 function @{ML [index] import in Variable}. This is similar |
|
257 to the attribute @{text "[no_vars]"} from Isabelle's user-level. |
249 *} |
258 *} |
250 |
259 |
251 ML{*fun no_vars ctxt thm = |
260 ML{*fun no_vars ctxt thm = |
252 let |
261 let |
253 val ((_, [thm']), _) = Variable.import true [thm] ctxt |
262 val ((_, [thm']), _) = Variable.import true [thm] ctxt |
493 *} |
502 *} |
494 |
503 |
495 ML{*fun (x, y) ||> f = (x, f y)*} |
504 ML{*fun (x, y) ||> f = (x, f y)*} |
496 |
505 |
497 text {* |
506 text {* |
|
507 These two functions can be used to avoid explicit @{text "lets"} for |
|
508 intermediate values in functions that return pairs. Suppose for example you |
|
509 want to separate a list of integers into two lists according to a |
|
510 treshold. For example if the treshold is @{ML "5"}, the list @{ML |
|
511 "[1,6,2,5,3,4]"} should be separated to @{ML "([1,2,3,4], [6,5])"}. You |
|
512 can implement this function more concisely as |
|
513 *} |
|
514 |
|
515 ML{*fun separate i [] = ([], []) |
|
516 | separate i (x::xs) = |
|
517 let |
|
518 val (los, grs) = separate i xs |
|
519 in |
|
520 if i <= x then (los, x::grs) else (x::los, grs) |
|
521 end*} |
|
522 |
|
523 text {* |
|
524 where however the return value of the recursive |
|
525 call is bound explicitly to the pair @{ML "(los, grs)" for los grs}. |
|
526 This function can equally be written as |
|
527 *} |
|
528 |
|
529 ML{*fun separate i [] = ([], []) |
|
530 | separate i (x::xs) = |
|
531 if i <= x |
|
532 then separate i xs ||> cons x |
|
533 else separate i xs |>> cons x*} |
|
534 |
|
535 text {* |
|
536 where no explicit @{text "let"} is needed. While in this example the gain is |
|
537 only small, in more complicated situations the benefit of avoiding @{text "lets"} |
|
538 can be substantial. |
|
539 |
498 With the combinator @{ML [index] "|->"} you can re-combine the elements from a pair. |
540 With the combinator @{ML [index] "|->"} you can re-combine the elements from a pair. |
499 This combinator is defined as |
541 This combinator is defined as |
500 *} |
542 *} |
501 |
543 |
502 ML{*fun (x, y) |-> f = f x y*} |
544 ML{*fun (x, y) |-> f = f x y*} |
683 It is also possible to define your own antiquotations. But you should |
727 It is also possible to define your own antiquotations. But you should |
684 exercise care when introducing new ones, as they can also make your |
728 exercise care when introducing new ones, as they can also make your |
685 code also difficult to read. In the next section we will see how the (build in) |
729 code also difficult to read. In the next section we will see how the (build in) |
686 antiquotation @{text "@{term \<dots>}"} can be used to construct terms. |
730 antiquotation @{text "@{term \<dots>}"} can be used to construct terms. |
687 A restriction of this antiquotation is that it does not allow you to |
731 A restriction of this antiquotation is that it does not allow you to |
688 use schematic variables. If you want an antiquotation that does not |
732 use schematic variables. If you want to have an antiquotation that does not |
689 have this restriction, you can implement your own using the |
733 have this restriction, you can implement your own using the |
690 function @{ML [index] ML_Antiquote.inline}. The code is as follows. |
734 function @{ML [index] ML_Antiquote.inline}. The code is as follows. |
691 *} |
735 *} |
692 |
736 |
693 ML %linenosgray{*ML_Antiquote.inline "term_pat" |
737 ML %linenosgray{*ML_Antiquote.inline "term_pat" |
696 s |> ProofContext.read_term_pattern ctxt |
740 s |> ProofContext.read_term_pattern ctxt |
697 |> ML_Syntax.print_term |
741 |> ML_Syntax.print_term |
698 |> ML_Syntax.atomic))*} |
742 |> ML_Syntax.atomic))*} |
699 |
743 |
700 text {* |
744 text {* |
701 We call the new antiquotation @{text "term_pat"} (Line 1); the parser in Line |
745 The parser in Line 2 provides us with a context and a string; this string is |
702 2 provides us with a context and a string; this string is transformed into a |
746 transformed into a term using the function @{ML [index] read_term_pattern in |
703 term using the function @{ML [index] read_term_pattern in ProofContext} (Line 4); |
747 ProofContext} (Line 4); the next two lines print the term so that the |
704 the next two lines print the term so that the ML-system can understand |
748 ML-system can understand them. An example of this antiquotation is as |
705 them. An example of this antiquotation is as follows. |
749 follows. |
706 |
750 |
707 @{ML_response_fake [display,gray] |
751 @{ML_response_fake [display,gray] |
708 "@{term_pat \"Suc (?x::nat)\"}" |
752 "@{term_pat \"Suc (?x::nat)\"}" |
709 "Const (\"Suc\", \"nat \<Rightarrow> nat\") $ Var ((\"x\", 0), \"nat\")"} |
753 "Const (\"Suc\", \"nat \<Rightarrow> nat\") $ Var ((\"x\", 0), \"nat\")"} |
710 |
754 |
772 abstractions for printing purposes, and so should be treated only as |
816 abstractions for printing purposes, and so should be treated only as |
773 ``comments''. Application in Isabelle is realised with the term-constructor |
817 ``comments''. Application in Isabelle is realised with the term-constructor |
774 @{ML $}. |
818 @{ML $}. |
775 |
819 |
776 |
820 |
777 Isabelle makes a distinction between \emph{free} variables (term-constructor @{ML Free}) |
821 Isabelle makes a distinction between \emph{free} variables (term-constructor |
778 and variables (term-constructor @{ML Var}). The latter correspond to the schematic |
822 @{ML Free} and written in blue colour) and \emph{schematic} variables |
779 variables that when printed show up with a question mark in front of them. Consider |
823 (term-constructor @{ML Var} and written with a leading question mark). The |
780 the following two examples |
824 latter correspond to the schematic variables that when printed show up with |
|
825 a question mark in front of them. Consider the following two examples |
|
826 |
781 |
827 |
782 @{ML_response_fake [display, gray] |
828 @{ML_response_fake [display, gray] |
783 "let |
829 "let |
784 val v1 = Var ((\"x\", 3), @{typ bool}) |
830 val v1 = Var ((\"x\", 3), @{typ bool}) |
785 val v2 = Var ((\"x1\", 3), @{typ bool}) |
831 val v2 = Var ((\"x1\", 3), @{typ bool}) |
984 then the variable @{text "Free (\"x\", \"int\")"} is \emph{not} abstracted. |
1030 then the variable @{text "Free (\"x\", \"int\")"} is \emph{not} abstracted. |
985 This is a fundamental principle |
1031 This is a fundamental principle |
986 of Church-style typing, where variables with the same name still differ, if they |
1032 of Church-style typing, where variables with the same name still differ, if they |
987 have different type. |
1033 have different type. |
988 |
1034 |
989 There is also the function @{ML [index] subst_free} with which terms can |
1035 There is also the function @{ML [index] subst_free} with which terms can be |
990 be replaced by other terms. For example below, we will replace in |
1036 replaced by other terms. For example below, we will replace in @{term |
991 @{term "(f::nat \<Rightarrow> nat \<Rightarrow> nat) 0 x"} |
1037 "(f::nat \<Rightarrow> nat \<Rightarrow> nat) 0 x"} the subterm @{term "(f::nat \<Rightarrow> nat \<Rightarrow> nat) 0"} by |
992 the subterm @{term "(f::nat \<Rightarrow> nat \<Rightarrow> nat) 0"} by @{term y}, and @{term x} by @{term True}. |
1038 @{term y}, and @{term x} by @{term True}. |
993 |
1039 |
994 @{ML_response_fake [display,gray] |
1040 @{ML_response_fake [display,gray] |
995 "let |
1041 "let |
996 val s1 = (@{term \"(f::nat \<Rightarrow> nat \<Rightarrow> nat) 0\"}, @{term \"y::nat \<Rightarrow> nat\"}) |
1042 val s1 = (@{term \"(f::nat \<Rightarrow> nat \<Rightarrow> nat) 0\"}, @{term \"y::nat \<Rightarrow> nat\"}) |
997 val s2 = (@{term \"x::nat\"}, @{term \"True\"}) |
1043 val s2 = (@{term \"x::nat\"}, @{term \"True\"}) |
1010 val trm = @{term \"(\<lambda>x::nat. x)\"} |
1056 val trm = @{term \"(\<lambda>x::nat. x)\"} |
1011 in |
1057 in |
1012 subst_free [s] trm |
1058 subst_free [s] trm |
1013 end" |
1059 end" |
1014 "Free (\"x\", \"nat\")"} |
1060 "Free (\"x\", \"nat\")"} |
|
1061 |
|
1062 Similarly the function @{ML [index] subst_bounds}, replaces lose bound |
|
1063 variables with terms. To see how this function works, let us implement a |
|
1064 function that strips off the outermost quantifiers in a term. |
|
1065 *} |
|
1066 |
|
1067 ML {* |
|
1068 subst_bounds ([Free ("x", @{typ nat}), Free ("y", @{typ bool})], |
|
1069 (Bound 1 $ Bound 0)) |
|
1070 *} |
|
1071 |
|
1072 |
|
1073 ML{*fun strip_alls (Const ("All", _) $ Abs (n, T, t)) = |
|
1074 strip_alls t |>> cons (Free (n, T)) |
|
1075 | strip_alls t = ([], t) *} |
|
1076 |
|
1077 text {* |
|
1078 The function returns a pair consisting of the stripped off variables and |
|
1079 the body of the universal quantifications. For example |
|
1080 |
|
1081 @{ML_response_fake [display, gray] |
|
1082 "strip_alls @{term \"\<forall>x y. x = (y::bool)\"}" |
|
1083 "([Free (\"x\", \"bool\"), Free (\"y\", \"bool\")], |
|
1084 Const (\"op =\", \<dots>) $ Bound 1 $ Bound 0)"} |
|
1085 |
|
1086 With the function @{ML subst_bounds}, you can replace the lose |
|
1087 @{ML [index] Bound}s with the stripped off variables. |
|
1088 |
|
1089 @{ML_response_fake [display, gray, linenos] |
|
1090 "let |
|
1091 val (vrs, trm) = strip_alls @{term \"\<forall>x y. x = (y::bool)\"} |
|
1092 in |
|
1093 subst_bounds (rev vrs, trm) |
|
1094 |> Syntax.string_of_term @{context} |
|
1095 |> tracing |
|
1096 end" |
|
1097 "x = y"} |
|
1098 |
|
1099 Note that in Line 4 we had to reverse the list of variables that @{ML strip_alls} |
|
1100 returned. The reason is that the head of the list the function @{ML subst_bounds} |
|
1101 takes is the replacement for @{ML "Bound 0"}, the next element for @{ML "Bound 1"} |
|
1102 and so on. |
1015 |
1103 |
1016 There are many convenient functions that construct specific HOL-terms. For |
1104 There are many convenient functions that construct specific HOL-terms. For |
1017 example @{ML [index] mk_eq in HOLogic} constructs an equality out of two terms. |
1105 example @{ML [index] mk_eq in HOLogic} constructs an equality out of two terms. |
1018 The types needed in this equality are calculated from the type of the |
1106 The types needed in this equality are calculated from the type of the |
1019 arguments. For example |
1107 arguments. For example |