57 |
57 |
58 Once a portion of code is relatively stable, you usually want to export it |
58 Once a portion of code is relatively stable, you usually want to export it |
59 to a separate ML-file. Such files can then be included somewhere inside a |
59 to a separate ML-file. Such files can then be included somewhere inside a |
60 theory by using the command \isacommand{use}. For example |
60 theory by using the command \isacommand{use}. For example |
61 |
61 |
62 \begin{center} |
62 \begin{quote} |
63 \begin{tabular}{@ {}l} |
63 \begin{tabular}{@ {}l} |
64 \isacommand{theory} FirstSteps\\ |
64 \isacommand{theory} FirstSteps\\ |
65 \isacommand{imports} Main\\ |
65 \isacommand{imports} Main\\ |
66 \isacommand{uses}~@{text "(\"file_to_be_included.ML\")"} @{text "\<dots>"}\\ |
66 \isacommand{uses}~@{text "(\"file_to_be_included.ML\")"} @{text "\<dots>"}\\ |
67 \isacommand{begin}\\ |
67 \isacommand{begin}\\ |
68 \ldots\\ |
68 \ldots\\ |
69 \isacommand{use}~@{text "\"file_to_be_included.ML\""}\\ |
69 \isacommand{use}~@{text "\"file_to_be_included.ML\""}\\ |
70 \ldots |
70 \ldots |
71 \end{tabular} |
71 \end{tabular} |
72 \end{center} |
72 \end{quote} |
73 |
73 |
74 The \isacommand{uses}-command in the header of the theory is needed in order |
74 The \isacommand{uses}-command in the header of the theory is needed in order |
75 to indicate the dependency of the theory on the ML-file. Alternatively, the |
75 to indicate the dependency of the theory on the ML-file. Alternatively, the |
76 file can be included by just writing in the header |
76 file can be included by just writing in the header |
77 |
77 |
78 \begin{center} |
78 \begin{quote} |
79 \begin{tabular}{@ {}l} |
79 \begin{tabular}{@ {}l} |
80 \isacommand{theory} FirstSteps\\ |
80 \isacommand{theory} FirstSteps\\ |
81 \isacommand{imports} Main\\ |
81 \isacommand{imports} Main\\ |
82 \isacommand{uses} @{text "\"file_to_be_included.ML\""} @{text "\<dots>"}\\ |
82 \isacommand{uses} @{text "\"file_to_be_included.ML\""} @{text "\<dots>"}\\ |
83 \isacommand{begin}\\ |
83 \isacommand{begin}\\ |
84 \ldots |
84 \ldots |
85 \end{tabular} |
85 \end{tabular} |
86 \end{center} |
86 \end{quote} |
87 |
87 |
88 Note that no parentheses are given this time. |
88 Note that no parentheses are given this time. |
89 *} |
89 *} |
90 |
90 |
91 section {* Debugging and Printing\label{sec:printing} *} |
91 section {* Debugging and Printing\label{sec:printing} *} |
179 "\"1\""} |
179 "\"1\""} |
180 |
180 |
181 A @{ML_type cterm} can be transformed into a string by the following function. |
181 A @{ML_type cterm} can be transformed into a string by the following function. |
182 *} |
182 *} |
183 |
183 |
184 ML{*fun str_of_cterm ctxt t = |
184 ML{*fun string_of_cterm ctxt t = |
185 Syntax.string_of_term ctxt (term_of t)*} |
185 Syntax.string_of_term ctxt (term_of t)*} |
186 |
186 |
187 text {* |
187 text {* |
188 In this example the function @{ML term_of} extracts the @{ML_type term} from |
188 In this example the function @{ML term_of} extracts the @{ML_type term} from |
189 a @{ML_type cterm}. If there are more than one @{ML_type cterm}s to be |
189 a @{ML_type cterm}. If there are more than one @{ML_type cterm}s to be |
190 printed, you can use the function @{ML commas} to separate them. |
190 printed, you can use the function @{ML commas} to separate them. |
191 *} |
191 *} |
192 |
192 |
193 ML{*fun str_of_cterms ctxt ts = |
193 ML{*fun string_of_cterms ctxt ts = |
194 commas (map (str_of_cterm ctxt) ts)*} |
194 commas (map (string_of_cterm ctxt) ts)*} |
195 |
195 |
196 text {* |
196 text {* |
197 The easiest way to get the string of a theorem is to transform it |
197 The easiest way to get the string of a theorem is to transform it |
198 into a @{ML_type cterm} using the function @{ML crep_thm}. |
198 into a @{ML_type cterm} using the function @{ML crep_thm}. |
199 *} |
199 *} |
200 |
200 |
201 ML{*fun str_of_thm ctxt thm = |
201 ML{*fun string_of_thm ctxt thm = |
202 str_of_cterm ctxt (#prop (crep_thm thm))*} |
202 string_of_cterm ctxt (#prop (crep_thm thm))*} |
203 |
203 |
204 text {* |
204 text {* |
205 Theorems also include schematic variables, such as @{text "?P"}, |
205 Theorems also include schematic variables, such as @{text "?P"}, |
206 @{text "?Q"} and so on. |
206 @{text "?Q"} and so on. |
207 |
207 |
208 @{ML_response_fake [display, gray] |
208 @{ML_response_fake [display, gray] |
209 "writeln (str_of_thm @{context} @{thm conjI})" |
209 "writeln (string_of_thm @{context} @{thm conjI})" |
210 "\<lbrakk>?P; ?Q\<rbrakk> \<Longrightarrow> ?P \<and> ?Q"} |
210 "\<lbrakk>?P; ?Q\<rbrakk> \<Longrightarrow> ?P \<and> ?Q"} |
211 |
211 |
212 In order to improve the readability of theorems we convert |
212 In order to improve the readability of theorems we convert |
213 these schematic variables into free variables using the |
213 these schematic variables into free variables using the |
214 function @{ML Variable.import_thms}. |
214 function @{ML Variable.import_thms}. |
219 val ((_, [thm']), _) = Variable.import_thms true [thm] ctxt |
219 val ((_, [thm']), _) = Variable.import_thms true [thm] ctxt |
220 in |
220 in |
221 thm' |
221 thm' |
222 end |
222 end |
223 |
223 |
224 fun str_of_thm_no_vars ctxt thm = |
224 fun string_of_thm_no_vars ctxt thm = |
225 str_of_cterm ctxt (#prop (crep_thm (no_vars ctxt thm)))*} |
225 string_of_cterm ctxt (#prop (crep_thm (no_vars ctxt thm)))*} |
226 |
226 |
227 text {* |
227 text {* |
228 Theorem @{thm [source] conjI} is now printed as follows: |
228 Theorem @{thm [source] conjI} is now printed as follows: |
229 |
229 |
230 @{ML_response_fake [display, gray] |
230 @{ML_response_fake [display, gray] |
231 "writeln (str_of_thm_no_vars @{context} @{thm conjI})" |
231 "writeln (string_of_thm_no_vars @{context} @{thm conjI})" |
232 "\<lbrakk>P; Q\<rbrakk> \<Longrightarrow> P \<and> Q"} |
232 "\<lbrakk>P; Q\<rbrakk> \<Longrightarrow> P \<and> Q"} |
233 |
233 |
234 Again the function @{ML commas} helps with printing more than one theorem. |
234 Again the function @{ML commas} helps with printing more than one theorem. |
235 *} |
235 *} |
236 |
236 |
237 ML{*fun str_of_thms ctxt thms = |
237 ML{*fun string_of_thms ctxt thms = |
238 commas (map (str_of_thm ctxt) thms) |
238 commas (map (string_of_thm ctxt) thms) |
239 |
239 |
240 fun str_of_thms_no_vars ctxt thms = |
240 fun string_of_thms_no_vars ctxt thms = |
241 commas (map (str_of_thm_no_vars ctxt) thms) *} |
241 commas (map (string_of_thm_no_vars ctxt) thms) *} |
242 |
242 |
243 section {* Combinators\label{sec:combinators} *} |
243 section {* Combinators\label{sec:combinators} *} |
244 |
244 |
245 text {* |
245 text {* |
246 (FIXME: Calling convention) |
|
247 |
|
248 For beginners perhaps the most puzzling parts in the existing code of Isabelle are |
246 For beginners perhaps the most puzzling parts in the existing code of Isabelle are |
249 the combinators. At first they seem to greatly obstruct the |
247 the combinators. At first they seem to greatly obstruct the |
250 comprehension of the code, but after getting familiar with them, they |
248 comprehension of the code, but after getting familiar with them, they |
251 actually ease the understanding and also the programming. |
249 actually ease the understanding and also the programming. |
252 |
250 |
285 the first component of the pair (Line 4) and finally incrementing the first |
283 the first component of the pair (Line 4) and finally incrementing the first |
286 component by 4 (Line 5). This kind of cascading manipulations of values is quite |
284 component by 4 (Line 5). This kind of cascading manipulations of values is quite |
287 common when dealing with theories (for example by adding a definition, followed by |
285 common when dealing with theories (for example by adding a definition, followed by |
288 lemmas and so on). The reverse application allows you to read what happens in |
286 lemmas and so on). The reverse application allows you to read what happens in |
289 a top-down manner. This kind of coding should also be familiar, |
287 a top-down manner. This kind of coding should also be familiar, |
290 if you have been exposed to Haskell's do-notation. Writing the function @{ML inc_by_five} using |
288 if you have been exposed to Haskell's {\it do}-notation. Writing the function |
291 the reverse application is much clearer than writing |
289 @{ML inc_by_five} using the reverse application is much clearer than writing |
292 *} |
290 *} |
293 |
291 |
294 ML{*fun inc_by_five x = fst ((fn x => (x, x)) (x + 1)) + 4*} |
292 ML{*fun inc_by_five x = fst ((fn x => (x, x)) (x + 1)) + 4*} |
295 |
293 |
296 text {* or *} |
294 text {* or *} |
541 end*} |
540 end*} |
542 |
541 |
543 text {* |
542 text {* |
544 The function @{ML dest_ss in MetaSimplifier} returns a record containing all |
543 The function @{ML dest_ss in MetaSimplifier} returns a record containing all |
545 information stored in the simpset, but we are only interested in the names of the |
544 information stored in the simpset, but we are only interested in the names of the |
546 simp-rules. So now you can feed in the current simpset into this function. |
545 simp-rules. Now you can feed in the current simpset into this function. |
547 The current simpset can be referred to using the antiquotation @{text "@{simpset}"}. |
546 The current simpset can be referred to using the antiquotation @{text "@{simpset}"}. |
548 |
547 |
549 @{ML_response_fake [display,gray] |
548 @{ML_response_fake [display,gray] |
550 "get_thm_names_from_ss @{simpset}" |
549 "get_thm_names_from_ss @{simpset}" |
551 "[\"Nat.of_nat_eq_id\", \"Int.of_int_eq_id\", \"Nat.One_nat_def\", \<dots>]"} |
550 "[\"Nat.of_nat_eq_id\", \"Int.of_int_eq_id\", \"Nat.One_nat_def\", \<dots>]"} |
553 Again, this way of referencing simpsets makes you independent from additions |
552 Again, this way of referencing simpsets makes you independent from additions |
554 of lemmas to the simpset by the user that potentially cause loops. |
553 of lemmas to the simpset by the user that potentially cause loops. |
555 |
554 |
556 On the ML-level of Isabelle, you often have to work with qualified names; |
555 On the ML-level of Isabelle, you often have to work with qualified names; |
557 these are strings with some additional information, such as positional information |
556 these are strings with some additional information, such as positional information |
558 and qualifiers. Such bindings can be generated with the antiquotation |
557 and qualifiers. Such qualified names can be generated with the antiquotation |
559 @{text "@{binding \<dots>}"}. |
558 @{text "@{binding \<dots>}"}. |
560 |
559 |
561 @{ML_response [display,gray] |
560 @{ML_response [display,gray] |
562 "@{binding \"name\"}" |
561 "@{binding \"name\"}" |
563 "name"} |
562 "name"} |
603 |
603 |
604 section {* Terms and Types *} |
604 section {* Terms and Types *} |
605 |
605 |
606 text {* |
606 text {* |
607 One way to construct Isabelle terms, is by using the antiquotation |
607 One way to construct Isabelle terms, is by using the antiquotation |
608 \mbox{@{text "@{term \<dots>}"}}. For example: |
608 \mbox{@{text "@{term \<dots>}"}}. For example |
609 |
609 |
610 @{ML_response [display,gray] |
610 @{ML_response [display,gray] |
611 "@{term \"(a::nat) + b = c\"}" |
611 "@{term \"(a::nat) + b = c\"}" |
612 "Const (\"op =\", \<dots>) $ |
612 "Const (\"op =\", \<dots>) $ |
613 (Const (\"HOL.plus_class.plus\", \<dots>) $ \<dots> $ \<dots>) $ \<dots>"} |
613 (Const (\"HOL.plus_class.plus\", \<dots>) $ \<dots> $ \<dots>) $ \<dots>"} |
614 |
614 |
615 will show the term @{term "(a::nat) + b = c"}, but printed using the internal |
615 will show the term @{term "(a::nat) + b = c"}, but printed using the internal |
616 representation corresponding to the data type @{ML_type "term"}. |
616 representation corresponding to the datatype @{ML_type "term"}. Since Isabelle |
617 |
617 uses Church-style terms, the datatype @{ML_type term} must be defined in |
618 This internal representation uses the usual de Bruijn index mechanism---where |
618 conjunction with types, that is the datatype @{ML_type typ}: |
619 bound variables are represented by the constructor @{ML Bound}. The index in |
619 *} |
|
620 |
|
621 ML_val{*datatype typ = |
|
622 Type of string * typ list |
|
623 | TFree of string * sort |
|
624 | TVar of indexname * sort |
|
625 datatype term = |
|
626 Const of string * typ |
|
627 | Free of string * typ |
|
628 | Var of indexname * typ |
|
629 | Bound of int |
|
630 | Abs of string * typ * term |
|
631 | $ of term * term *} |
|
632 |
|
633 text {* |
|
634 The datatype for terms uses the usual de Bruijn index mechanism---where |
|
635 bound variables are represented by the constructor @{ML Bound}. |
|
636 |
|
637 @{ML_response_fake [display, gray] |
|
638 "@{term \"\<lambda>x y. x y\"}" |
|
639 "Abs (\"x\", \"'a \<Rightarrow> 'b\", Abs (\"y\", \"'a\", Bound 1 $ Bound 0))"} |
|
640 |
|
641 The index in |
620 @{ML Bound} refers to the number of Abstractions (@{ML Abs}) we have to skip |
642 @{ML Bound} refers to the number of Abstractions (@{ML Abs}) we have to skip |
621 until we hit the @{ML Abs} that binds the corresponding variable. Note that |
643 until we hit the @{ML Abs} that binds the corresponding variable. Note that |
622 the names of bound variables are kept at abstractions for printing purposes, |
644 the names of bound variables are kept at abstractions for printing purposes, |
623 and so should be treated only as ``comments''. Application in Isabelle is |
645 and so should be treated only as ``comments''. Application in Isabelle is |
624 realised with the term-constructor @{ML $}. |
646 realised with the term-constructor @{ML $}. |
|
647 |
|
648 Isabelle makes a distinction between \emph{free} variables (term-constructor @{ML Free}) |
|
649 and variables (term-constructor @{ML Var}). The latter correspond to the schematic |
|
650 variables that show up with a question mark in front of them. Consider the following |
|
651 two examples |
|
652 |
|
653 @{ML_response_fake [display, gray] |
|
654 "let |
|
655 val v1 = Var ((\"x\", 3), @{typ bool}) |
|
656 val v2 = Var ((\"x1\",3), @{typ bool}) |
|
657 in |
|
658 writeln (Syntax.string_of_term @{context} v1); |
|
659 writeln (Syntax.string_of_term @{context} v2) |
|
660 end" |
|
661 "?x3 |
|
662 ?x1.3"} |
|
663 |
|
664 This is different from a free variable |
|
665 |
|
666 @{ML_response_fake [display, gray] |
|
667 "@{term \"x\"}" |
|
668 "x"} |
|
669 |
|
670 When constructing terms, you are usually concerned with free variables (for example |
|
671 you cannot construct schematic variables using the antiquotation @{text "@{term \<dots>}"}). |
|
672 If you deal with theorems, you have to observe the distinction. The same holds |
|
673 for types. |
625 |
674 |
626 \begin{readmore} |
675 \begin{readmore} |
627 Terms are described in detail in \isccite{sec:terms}. Their |
676 Terms and types are described in detail in \isccite{sec:terms}. Their |
628 definition and many useful operations are implemented in @{ML_file "Pure/term.ML"}. |
677 definition and many useful operations are implemented in @{ML_file "Pure/term.ML"}. |
629 \end{readmore} |
678 \end{readmore} |
630 |
679 |
631 Constructing terms via antiquotations has the advantage that only typable |
680 Constructing terms via antiquotations has the advantage that only typable |
632 terms can be constructed. For example |
681 terms can be constructed. For example |
633 |
682 |
634 @{ML_response_fake_both [display,gray] |
683 @{ML_response_fake_both [display,gray] |
635 "@{term \"(x::nat) x\"}" |
684 "@{term \"x x\"}" |
636 "Type unification failed \<dots>"} |
685 "Type unification failed: Occurs check!"} |
637 |
686 |
638 raises a typing error, while it perfectly ok to construct the term |
687 raises a typing error, while it perfectly ok to construct the term |
639 |
688 |
640 @{ML [display,gray] "Free (\"x\", @{typ nat}) $ Free (\"x\", @{typ nat})"} |
689 @{ML [display,gray] "Free (\"x\", @{typ nat}) $ Free (\"x\", @{typ nat})"} |
641 |
690 |
863 by @{ML "Const (\"All\", some_type)" for some_type}. However, if you look at |
911 by @{ML "Const (\"All\", some_type)" for some_type}. However, if you look at |
864 |
912 |
865 @{ML_response [display,gray] "@{term \"Nil\"}" "Const (\"List.list.Nil\", \<dots>)"} |
913 @{ML_response [display,gray] "@{term \"Nil\"}" "Const (\"List.list.Nil\", \<dots>)"} |
866 |
914 |
867 the name of the constant @{text "Nil"} depends on the theory in which the |
915 the name of the constant @{text "Nil"} depends on the theory in which the |
868 term constructor is defined (@{text "List"}) and also in which data type |
916 term constructor is defined (@{text "List"}) and also in which datatype |
869 (@{text "list"}). Even worse, some constants have a name involving |
917 (@{text "list"}). Even worse, some constants have a name involving |
870 type-classes. Consider for example the constants for @{term "zero"} and |
918 type-classes. Consider for example the constants for @{term "zero"} and |
871 \mbox{@{text "(op *)"}}: |
919 \mbox{@{text "(op *)"}}: |
872 |
920 |
873 @{ML_response [display,gray] "(@{term \"0::nat\"}, @{term \"op *\"})" |
921 @{ML_response [display,gray] "(@{term \"0::nat\"}, @{term \"op *\"})" |
875 Const (\"HOL.times_class.times\", \<dots>))"} |
923 Const (\"HOL.times_class.times\", \<dots>))"} |
876 |
924 |
877 While you could use the complete name, for example |
925 While you could use the complete name, for example |
878 @{ML "Const (\"List.list.Nil\", some_type)" for some_type}, for referring to or |
926 @{ML "Const (\"List.list.Nil\", some_type)" for some_type}, for referring to or |
879 matching against @{text "Nil"}, this would make the code rather brittle. |
927 matching against @{text "Nil"}, this would make the code rather brittle. |
880 The reason is that the theory and the name of the data type can easily change. |
928 The reason is that the theory and the name of the datatype can easily change. |
881 To make the code more robust, it is better to use the antiquotation |
929 To make the code more robust, it is better to use the antiquotation |
882 @{text "@{const_name \<dots>}"}. With this antiquotation you can harness the |
930 @{text "@{const_name \<dots>}"}. With this antiquotation you can harness the |
883 variable parts of the constant's name. Therefore a function for |
931 variable parts of the constant's name. Therefore a function for |
884 matching against constants that have a polymorphic type should |
932 matching against constants that have a polymorphic type should |
885 be written as follows. |
933 be written as follows. |
1908 @{ML_response_fake [display,gray] |
1961 @{ML_response_fake [display,gray] |
1909 "tell_type @{context} @{term \"min (Suc 0)\"}" |
1962 "tell_type @{context} @{term \"min (Suc 0)\"}" |
1910 "The term \"min (Suc 0)\" has type \"nat \<Rightarrow> nat\"."} |
1963 "The term \"min (Suc 0)\" has type \"nat \<Rightarrow> nat\"."} |
1911 |
1964 |
1912 To see the proper linebreaking, you can try out the function on a bigger term |
1965 To see the proper linebreaking, you can try out the function on a bigger term |
1913 and type. |
1966 and type. For example: |
1914 |
1967 |
1915 @{ML_response_fake [display,gray] |
1968 @{ML_response_fake [display,gray] |
1916 "tell_type @{context} @{term \"op = (op = (op = (op = (op = op =))))\"}" |
1969 "tell_type @{context} @{term \"op = (op = (op = (op = (op = op =))))\"}" |
1917 "The term \"op = (op = (op = (op = (op = op =))))\" has type |
1970 "The term \"op = (op = (op = (op = (op = op =))))\" has type |
1918 \"((((('a \<Rightarrow> 'a \<Rightarrow> bool) \<Rightarrow> bool) \<Rightarrow> bool) \<Rightarrow> bool) \<Rightarrow> bool) \<Rightarrow> bool\"."} |
1971 \"((((('a \<Rightarrow> 'a \<Rightarrow> bool) \<Rightarrow> bool) \<Rightarrow> bool) \<Rightarrow> bool) \<Rightarrow> bool) \<Rightarrow> bool\"."} |
1919 |
1972 |
1920 *} |
1973 *} |
1921 |
1974 |
|
1975 ML {* pprint (Pretty.big_list "header" (map (Pretty.str o string_of_int) (4 upto 10))) *} |
|
1976 |
|
1977 text {* |
|
1978 chunks inserts forced breaks (unlike blk where you have to do this yourself) |
|
1979 *} |
|
1980 |
|
1981 ML {* (Pretty.chunks [Pretty.str "a", Pretty.str "b"], |
|
1982 Pretty.blk (0, [Pretty.str "a", Pretty.str "b"])) *} |
|
1983 |
|
1984 ML {* |
|
1985 fun setmp_show_all_types f = |
|
1986 setmp show_all_types |
|
1987 (! show_types orelse ! show_sorts orelse ! show_all_types) f; |
|
1988 |
|
1989 val ctxt = @{context}; |
|
1990 val t1 = @{term "undefined::nat"}; |
|
1991 val t2 = @{term "Suc y"}; |
|
1992 val pty = Pretty.block (Pretty.breaks |
|
1993 [(setmp show_question_marks false o setmp_show_all_types) |
|
1994 (Syntax.pretty_term ctxt) t1, |
|
1995 Pretty.str "=", Syntax.pretty_term ctxt t2]); |
|
1996 pty |> Pretty.string_of |> priority |
|
1997 *} |
|
1998 |
|
1999 text {* the infrastructure of Syntax-pretty-term makes sure it is printed nicely *} |
|
2000 |
|
2001 |
|
2002 ML {* Pretty.mark Markup.hilite (Pretty.str "foo") |> Pretty.string_of |> writeln *} |
|
2003 ML {* (Pretty.str "bar") |> Pretty.string_of |> writeln *} |
|
2004 |
|
2005 |
|
2006 ML {* Pretty.mark Markup.subgoal (Pretty.str "foo") |> Pretty.string_of |> writeln *} |
|
2007 ML {* (Pretty.str "bar") |> Pretty.string_of |> writeln *} |
|
2008 |
1922 text {* |
2009 text {* |
1923 Still to be done: |
2010 Still to be done: |
1924 |
|
1925 @{ML Pretty.big_list}, |
|
1926 |
|
1927 @{ML Pretty.chunks} |
|
1928 |
|
1929 equations |
|
1930 |
|
1931 colours |
|
1932 |
2011 |
1933 What happens with big formulae? |
2012 What happens with big formulae? |
1934 |
2013 |
1935 \begin{readmore} |
2014 \begin{readmore} |
1936 The general infrastructure for pretty-printing is implemented in the file |
2015 The general infrastructure for pretty-printing is implemented in the file |
1937 @{ML_file "Pure/General/pretty.ML"}. The file @{ML_file "Pure/Syntax/syntax.ML"} |
2016 @{ML_file "Pure/General/pretty.ML"}. The file @{ML_file "Pure/Syntax/syntax.ML"} |
1938 contains pretty-printing functions for terms, types, theorems and so on. |
2017 contains pretty-printing functions for terms, types, theorems and so on. |
|
2018 |
|
2019 @{ML_file "Pure/General/markup.ML"} |
1939 \end{readmore} |
2020 \end{readmore} |
1940 *} |
2021 *} |
1941 |
2022 |
|
2023 text {* |
|
2024 printing into the goal buffer as part of the proof state |
|
2025 *} |
|
2026 |
|
2027 |
|
2028 ML {* Pretty.mark Markup.hilite (Pretty.str "foo") |> Pretty.string_of |> writeln *} |
|
2029 ML {* (Pretty.str "bar") |> Pretty.string_of |> writeln *} |
|
2030 |
|
2031 text {* writing into the goal buffer *} |
|
2032 |
|
2033 ML {* fun my_hook interactive state = |
|
2034 (interactive ? Proof.goal_message (fn () => Pretty.str |
|
2035 "foo")) state |
|
2036 *} |
|
2037 |
|
2038 setup {* Context.theory_map (Specification.add_theorem_hook my_hook) *} |
|
2039 |
|
2040 lemma "False" |
|
2041 oops |
|
2042 |
|
2043 |
1942 section {* Misc (TBD) *} |
2044 section {* Misc (TBD) *} |
1943 |
2045 |
1944 ML {*DatatypePackage.get_datatype @{theory} "List.list"*} |
2046 ML {*DatatypePackage.get_datatype @{theory} "List.list"*} |
1945 |
2047 |
1946 end |
2048 end |