192 |
195 |
193 ML {* Toplevel.program (fn () => innocent ()) *} |
196 ML {* Toplevel.program (fn () => innocent ()) *} |
194 *) |
197 *) |
195 |
198 |
196 text {* |
199 text {* |
197 Most often you want to inspect data of Isabelle's most basic datastructures, |
200 Most often you want to inspect data of Isabelle's most basic data |
198 namely @{ML_type term}, @{ML_type cterm} or @{ML_type thm}. Isabelle |
201 structures, namely @{ML_type term}, @{ML_type cterm} or @{ML_type |
199 contains elaborate pretty-printing functions for printing them (see Section |
202 thm}. Isabelle contains elaborate pretty-printing functions for printing |
200 \ref{sec:pretty}), but for quick-and-dirty solutions they are far too |
203 them (see Section \ref{sec:pretty}), but for quick-and-dirty solutions they |
201 unwieldy. One way to transform a term into a string is to use the function |
204 are a bit unwieldy. One way to transform a term into a string is to use the |
202 @{ML [index] string_of_term in Syntax}. |
205 function @{ML [index] string_of_term in Syntax} in structure @{ML_struct |
203 |
206 Syntax}, which we bind for more convenience to the toplevel. |
|
207 *} |
|
208 |
|
209 ML{*val string_of_term = Syntax.string_of_term*} |
|
210 |
|
211 text {* |
|
212 It can now be used as follows |
204 |
213 |
205 @{ML_response_fake [display,gray] |
214 @{ML_response_fake [display,gray] |
206 "Syntax.string_of_term @{context} @{term \"1::nat\"}" |
215 "string_of_term @{context} @{term \"1::nat\"}" |
207 "\"\\^E\\^Fterm\\^E\\^E\\^Fconst\\^Fname=HOL.one_class.one\\^E1\\^E\\^F\\^E\\^E\\^F\\^E\""} |
216 "\"\\^E\\^Fterm\\^E\\^E\\^Fconst\\^Fname=HOL.one_class.one\\^E1\\^E\\^F\\^E\\^E\\^F\\^E\""} |
208 |
217 |
209 This produces a string with some additional information encoded in it. The string |
218 This produces a string corrsponding to the term @{term [show_types] "1::nat"} with some |
210 can be properly printed by using either the function @{ML [index] writeln} or |
219 additional information encoded in it. The string can be properly printed by |
211 @{ML [index] tracing}: |
220 using either the function @{ML [index] writeln} or @{ML [index] tracing}: |
212 |
221 |
213 @{ML_response_fake [display,gray] |
222 @{ML_response_fake [display,gray] |
214 "writeln (Syntax.string_of_term @{context} @{term \"1::nat\"})" |
223 "writeln (string_of_term @{context} @{term \"1::nat\"})" |
215 "\"1\""} |
224 "\"1\""} |
216 |
225 |
217 or |
226 or |
218 |
227 |
219 @{ML_response_fake [display,gray] |
228 @{ML_response_fake [display,gray] |
220 "tracing (Syntax.string_of_term @{context} @{term \"1::nat\"})" |
229 "tracing (string_of_term @{context} @{term \"1::nat\"})" |
221 "\"1\""} |
230 "\"1\""} |
222 |
231 |
|
232 If there are more than one @{ML_type term}s to be printed, you can use the |
|
233 function @{ML [index] commas} to separate them. |
|
234 *} |
|
235 |
|
236 ML{*fun string_of_terms ctxt ts = |
|
237 commas (map (string_of_term ctxt) ts)*} |
|
238 |
|
239 text {* |
223 A @{ML_type cterm} can be transformed into a string by the following function. |
240 A @{ML_type cterm} can be transformed into a string by the following function. |
224 *} |
241 *} |
225 |
242 |
226 ML{*fun string_of_cterm ctxt t = |
243 ML{*fun string_of_cterm ctxt t = |
227 Syntax.string_of_term ctxt (term_of t)*} |
244 string_of_term ctxt (term_of t)*} |
228 |
245 |
229 text {* |
246 text {* |
230 In this example the function @{ML [index] term_of} extracts the @{ML_type term} from |
247 In this example the function @{ML [index] term_of} extracts the @{ML_type term} from |
231 a @{ML_type cterm}. If there are more than one @{ML_type cterm}s to be |
248 a @{ML_type cterm}. More than one @{ML_type cterm}s can again be printed |
232 printed, you can use the function @{ML [index] commas} to separate them. |
249 with @{ML [index] commas}. |
233 *} |
250 *} |
234 |
251 |
235 ML{*fun string_of_cterms ctxt ts = |
252 ML{*fun string_of_cterms ctxt cts = |
236 commas (map (string_of_cterm ctxt) ts)*} |
253 commas (map (string_of_cterm ctxt) cts)*} |
237 |
254 |
238 text {* |
255 text {* |
239 The easiest way to get the string of a theorem is to transform it |
256 The easiest way to get the string of a theorem is to transform it |
240 into a @{ML_type cterm} using the function @{ML [index] crep_thm}. |
257 into a @{ML_type cterm} using the function @{ML [index] crep_thm}. |
241 *} |
258 *} |
249 |
266 |
250 @{ML_response_fake [display, gray] |
267 @{ML_response_fake [display, gray] |
251 "tracing (string_of_thm @{context} @{thm conjI})" |
268 "tracing (string_of_thm @{context} @{thm conjI})" |
252 "\<lbrakk>?P; ?Q\<rbrakk> \<Longrightarrow> ?P \<and> ?Q"} |
269 "\<lbrakk>?P; ?Q\<rbrakk> \<Longrightarrow> ?P \<and> ?Q"} |
253 |
270 |
254 In order to improve the readability of theorems we convert |
271 In order to improve the readability of theorems we convert these schematic |
255 these schematic variables into free variables using the |
272 variables into free variables using the function @{ML [index] import in |
256 function @{ML [index] import in Variable}. This is similar |
273 Variable}. This is similar to the theorem attribute @{text "[no_vars]"} from |
257 to the attribute @{text "[no_vars]"} from Isabelle's user-level. |
274 Isabelle's user-level. |
258 *} |
275 *} |
259 |
276 |
260 ML{*fun no_vars ctxt thm = |
277 ML{*fun no_vars ctxt thm = |
261 let |
278 let |
262 val ((_, [thm']), _) = Variable.import true [thm] ctxt |
279 val ((_, [thm']), _) = Variable.import true [thm] ctxt |
597 |
614 |
598 ML{*val double = |
615 ML{*val double = |
599 (fn x => (x, x)) |
616 (fn x => (x, x)) |
600 #-> (fn x => fn y => x + y)*} |
617 #-> (fn x => fn y => x + y)*} |
601 |
618 |
602 text {* |
619 |
603 |
620 text {* |
604 (FIXME: find a good exercise for combinators) |
621 When using combinators for writing function in waterfall fashion, it is |
605 |
622 sometimes necessary to do some ``plumbing'' for fitting functions |
|
623 together. We have already seen such plumbing in the function @{ML |
|
624 apply_fresh_args}, where @{ML curry} is needed for making the function @{ML |
|
625 list_comb} that works over pairs to fit with the combinator @{ML "|>"}. Such |
|
626 plumbing is also needed in situations where a functions operate over lists, |
|
627 but one calculates only with a single entity. An example is the function |
|
628 @{ML [index] check_terms in Syntax}, whose purpose is to type-check a list |
|
629 of terms. |
|
630 |
|
631 @{ML_response_fake [display, gray] |
|
632 "let |
|
633 val ctxt = @{context} |
|
634 in |
|
635 map (Syntax.parse_term ctxt) [\"m + n\", \"m - (n::nat)\"] |
|
636 |> Syntax.check_terms ctxt |
|
637 |> string_of_terms ctxt |
|
638 |> tracing |
|
639 end" |
|
640 "m + n, m - n"} |
|
641 *} |
|
642 |
|
643 text {* |
|
644 In this example we obtain two terms with appropriate typing. However, if you |
|
645 have only a single term, then @{ML check_terms in Syntax} needs to be |
|
646 adapted. This can be done with the ``plumbing'' function @{ML |
|
647 singleton}.\footnote{There is in fact alread a function @{ML check_term in Syntax}, |
|
648 which however is defined in terms of @{ML singleton} and @{ML check_terms in |
|
649 Syntax}.} For example |
|
650 |
|
651 @{ML_response_fake [display, gray] |
|
652 "let |
|
653 val ctxt = @{context} |
|
654 in |
|
655 Syntax.parse_term ctxt \"m - (n::nat)\" |
|
656 |> singleton (Syntax.check_terms ctxt) |
|
657 |> string_of_term ctxt |
|
658 |> tracing |
|
659 end" |
|
660 "m - n"} |
|
661 |
606 \begin{readmore} |
662 \begin{readmore} |
607 The most frequently used combinators are defined in the files @{ML_file |
663 The most frequently used combinators are defined in the files @{ML_file |
608 "Pure/library.ML"} |
664 "Pure/library.ML"} |
609 and @{ML_file "Pure/General/basics.ML"}. Also \isccite{sec:ML-linear-trans} |
665 and @{ML_file "Pure/General/basics.ML"}. Also \isccite{sec:ML-linear-trans} |
610 contains further information about combinators. |
666 contains further information about combinators. |
611 \end{readmore} |
667 \end{readmore} |
612 |
668 |
613 (FIXME: say something about calling conventions) |
669 (FIXME: find a good exercise for combinators) |
614 |
670 |
615 (FIXME: say something about singleton) |
671 (FIXME: say something about calling conventions) |
616 *} |
672 *} |
617 |
673 |
618 |
674 |
619 section {* Antiquotations *} |
675 section {* Antiquotations *} |
620 |
676 |
829 "let |
885 "let |
830 val v1 = Var ((\"x\", 3), @{typ bool}) |
886 val v1 = Var ((\"x\", 3), @{typ bool}) |
831 val v2 = Var ((\"x1\", 3), @{typ bool}) |
887 val v2 = Var ((\"x1\", 3), @{typ bool}) |
832 val v3 = Free (\"x\", @{typ bool}) |
888 val v3 = Free (\"x\", @{typ bool}) |
833 in |
889 in |
834 map (Syntax.string_of_term @{context}) [v1, v2, v3] |
890 string_of_terms @{context} [v1, v2, v3] |
835 |> cat_lines |
|
836 |> tracing |
891 |> tracing |
837 end" |
892 end" |
838 "?x3 |
893 "?x3, ?x1.3, x"} |
839 ?x1.3 |
|
840 x"} |
|
841 |
894 |
842 When constructing terms, you are usually concerned with free variables (as mentioned earlier, |
895 When constructing terms, you are usually concerned with free variables (as mentioned earlier, |
843 you cannot construct schematic variables using the antiquotation @{text "@{term \<dots>}"}). |
896 you cannot construct schematic variables using the antiquotation @{text "@{term \<dots>}"}). |
844 If you deal with theorems, you have to, however, observe the distinction. A similar |
897 If you deal with theorems, you have to, however, observe the distinction. A similar |
845 distinction holds for types (see below). |
898 distinction holds for types (see below). |
1514 let val prems = Logic.strip_imp_prems t in |
1567 let val prems = Logic.strip_imp_prems t in |
1515 if i <= length prems |
1568 if i <= length prems |
1516 then let val (params,t) = strip_assums_all([], nth prems (i - 1)) |
1569 then let val (params,t) = strip_assums_all([], nth prems (i - 1)) |
1517 in subst_bounds(map Free params, t) end |
1570 in subst_bounds(map Free params, t) end |
1518 else error ("Not enough premises for prem" ^ string_of_int i ^ |
1571 else error ("Not enough premises for prem" ^ string_of_int i ^ |
1519 " in propositon: " ^ Syntax.string_of_term ctxt t) |
1572 " in propositon: " ^ string_of_term ctxt t) |
1520 end; |
1573 end; |
1521 *} |
1574 *} |
1522 |
1575 |
1523 ML {* |
1576 ML {* |
1524 strip_assums_all ([], @{term "\<And>x y. A x y"}) |
1577 strip_assums_all ([], @{term "\<And>x y. A x y"}) |