18 ``We will most likely never realize the full importance of painting the Tower,\\ |
18 ``We will most likely never realize the full importance of painting the Tower,\\ |
19 that it is the essential element in the conservation of metal works and the\\ |
19 that it is the essential element in the conservation of metal works and the\\ |
20 more meticulous the paint job, the longer the tower shall endure.''} \\[1ex] |
20 more meticulous the paint job, the longer the tower shall endure.''} \\[1ex] |
21 Gustave Eiffel, In his book {\em The 300-Meter Tower}.\footnote{The Eiffel Tower has been |
21 Gustave Eiffel, In his book {\em The 300-Meter Tower}.\footnote{The Eiffel Tower has been |
22 re-painted 18 times since its initial construction, an average of once every |
22 re-painted 18 times since its initial construction, an average of once every |
23 seven years. It takes more than a year for a team of 25 painters to paint the tower |
23 seven years. It takes more than one year for a team of 25 painters to paint the tower |
24 from top to bottom.} |
24 from top to bottom.} |
25 \end{flushright} |
25 \end{flushright} |
26 |
26 |
27 \medskip |
27 \medskip |
28 Isabelle programming is done in ML. Just like lemmas and proofs, ML-code for |
28 Isabelle programming is done in ML. Just like lemmas and proofs, ML-code for |
218 structures, namely @{ML_type term}, @{ML_type cterm} and @{ML_type |
218 structures, namely @{ML_type term}, @{ML_type cterm} and @{ML_type |
219 thm}. Isabelle contains elaborate pretty-printing functions for printing |
219 thm}. Isabelle contains elaborate pretty-printing functions for printing |
220 them (see Section \ref{sec:pretty}), but for quick-and-dirty solutions they |
220 them (see Section \ref{sec:pretty}), but for quick-and-dirty solutions they |
221 are a bit unwieldy. One way to transform a term into a string is to use the |
221 are a bit unwieldy. One way to transform a term into a string is to use the |
222 function @{ML_ind string_of_term in Syntax} in the structure @{ML_struct |
222 function @{ML_ind string_of_term in Syntax} in the structure @{ML_struct |
223 Syntax}, which we bind for more convenience to the toplevel. |
223 Syntax}. For more convenience, we bind this function to the toplevel. |
224 *} |
224 *} |
225 |
225 |
226 ML{*val string_of_term = Syntax.string_of_term*} |
226 ML{*val string_of_term = Syntax.string_of_term*} |
227 |
227 |
228 text {* |
228 text {* |
230 |
230 |
231 @{ML_response_fake [display,gray] |
231 @{ML_response_fake [display,gray] |
232 "string_of_term @{context} @{term \"1::nat\"}" |
232 "string_of_term @{context} @{term \"1::nat\"}" |
233 "\"\\^E\\^Fterm\\^E\\^E\\^Fconst\\^Fname=HOL.one_class.one\\^E1\\^E\\^F\\^E\\^E\\^F\\^E\""} |
233 "\"\\^E\\^Fterm\\^E\\^E\\^Fconst\\^Fname=HOL.one_class.one\\^E1\\^E\\^F\\^E\\^E\\^F\\^E\""} |
234 |
234 |
235 This produces a string corrsponding to the term @{term [show_types] "1::nat"} with some |
235 We obtain a string corrsponding to the term @{term [show_types] "1::nat"} with some |
236 additional information encoded in it. The string can be properly printed by |
236 additional information encoded in it. The string can be properly printed by |
237 using either the function @{ML_ind writeln} or @{ML_ind tracing}: |
237 using either the function @{ML_ind writeln} or @{ML_ind tracing}: |
238 |
238 |
239 @{ML_response_fake [display,gray] |
239 @{ML_response_fake [display,gray] |
240 "writeln (string_of_term @{context} @{term \"1::nat\"})" |
240 "writeln (string_of_term @{context} @{term \"1::nat\"})" |
276 |
276 |
277 ML{*fun string_of_thm ctxt thm = |
277 ML{*fun string_of_thm ctxt thm = |
278 string_of_term ctxt (prop_of thm)*} |
278 string_of_term ctxt (prop_of thm)*} |
279 |
279 |
280 text {* |
280 text {* |
281 Theorems also include schematic variables, such as @{text "?P"}, |
281 Theorems include schematic variables, such as @{text "?P"}, |
282 @{text "?Q"} and so on. They are needed in Isabelle in order to able to |
282 @{text "?Q"} and so on. They are needed in Isabelle in order to able to |
283 instantiate theorems when they are applied. For example the theorem |
283 instantiate theorems when they are applied. For example the theorem |
284 @{thm [source] conjI} shown below can be used for any (typable) |
284 @{thm [source] conjI} shown below can be used for any (typable) |
285 instantiation of @{text "?P"} and @{text "?Q"}. |
285 instantiation of @{text "?P"} and @{text "?Q"}. |
286 |
286 |
319 |
319 |
320 fun string_of_thms_no_vars ctxt thms = |
320 fun string_of_thms_no_vars ctxt thms = |
321 commas (map (string_of_thm_no_vars ctxt) thms) *} |
321 commas (map (string_of_thm_no_vars ctxt) thms) *} |
322 |
322 |
323 text {* |
323 text {* |
324 Note, that when printing out several parcels of information that |
324 Note that when printing out several ``parcels'' of information that |
325 semantically belong together, like a warning message consisting for example |
325 semantically belong together, like a warning message consisting of |
326 of a term and a type, you should try to keep this information together in a |
326 a term and its type, you should try to keep this information together in a |
327 single string. Therefore do \emph{not} print out information as |
327 single string. Therefore do \emph{not} print out information as |
328 |
328 |
329 @{ML_response_fake [display,gray] |
329 @{ML_response_fake [display,gray] |
330 "tracing \"First half,\"; |
330 "tracing \"First half,\"; |
331 tracing \"and second half.\"" |
331 tracing \"and second half.\"" |
371 *} |
377 *} |
372 |
378 |
373 ML{*fun K x = fn _ => x*} |
379 ML{*fun K x = fn _ => x*} |
374 |
380 |
375 text {* |
381 text {* |
376 @{ML K} ``wraps'' a function around the argument @{text "x"}. However, this |
382 @{ML K} ``wraps'' a function around @{text "x"} that ignores its argument. As a |
377 function ignores its argument. As a result, @{ML K} defines a constant function |
383 result, @{ML K} defines a constant function always returning @{text x}. |
378 always returning @{text x}. |
|
379 |
384 |
380 The next combinator is reverse application, @{ML_ind "|>" in Basics}, defined as: |
385 The next combinator is reverse application, @{ML_ind "|>" in Basics}, defined as: |
381 *} |
386 *} |
382 |
387 |
383 ML{*fun x |> f = f x*} |
388 ML{*fun x |> f = f x*} |
391 |> (fn x => (x, x)) |
396 |> (fn x => (x, x)) |
392 |> fst |
397 |> fst |
393 |> (fn x => x + 4)*} |
398 |> (fn x => x + 4)*} |
394 |
399 |
395 text {* |
400 text {* |
396 which increments its argument @{text x} by 5. It proceeds by first incrementing |
401 which increments its argument @{text x} by 5. It does this by first incrementing |
397 the argument by 1 (Line 2); then storing the result in a pair (Line 3); taking |
402 the argument by 1 (Line 2); then storing the result in a pair (Line 3); taking |
398 the first component of the pair (Line 4) and finally incrementing the first |
403 the first component of the pair (Line 4) and finally incrementing the first |
399 component by 4 (Line 5). This kind of cascading manipulations of values is quite |
404 component by 4 (Line 5). This kind of cascading manipulations of values is quite |
400 common when dealing with theories (for example by adding a definition, followed by |
405 common when dealing with theories (for example by adding a definition, followed by |
401 lemmas and so on). The reverse application allows you to read what happens in |
406 lemmas and so on). The reverse application allows you to read what happens in |
423 text {* |
428 text {* |
424 Another reason why the let-bindings in the code above are better to be |
429 Another reason why the let-bindings in the code above are better to be |
425 avoided: it is more than easy to get the intermediate values wrong, not to |
430 avoided: it is more than easy to get the intermediate values wrong, not to |
426 mention the nightmares the maintenance of this code causes! |
431 mention the nightmares the maintenance of this code causes! |
427 |
432 |
428 In Isabelle, a ``real world'' example for a function written in |
433 In Isabelle a ``real world'' example for a function written in |
429 the waterfall fashion might be the following code: |
434 the waterfall fashion might be the following code: |
430 *} |
435 *} |
431 |
436 |
432 ML %linenosgray{*fun apply_fresh_args f ctxt = |
437 ML %linenosgray{*fun apply_fresh_args f ctxt = |
433 f |> fastype_of |
438 f |> fastype_of |
494 text {* |
499 text {* |
495 which is the function composed of first the increment-by-one function and then |
500 which is the function composed of first the increment-by-one function and then |
496 increment-by-two, followed by increment-by-three. Again, the reverse function |
501 increment-by-two, followed by increment-by-three. Again, the reverse function |
497 composition allows you to read the code top-down. |
502 composition allows you to read the code top-down. |
498 |
503 |
499 The remaining combinators described in this section add convenience for the |
504 The remaining combinators we describe in this section add convenience for the |
500 ``waterfall method'' of writing functions. The combinator @{ML_ind tap in |
505 ``waterfall method'' of writing functions. The combinator @{ML_ind tap in |
501 Basics} allows you to get hold of an intermediate result (to do some |
506 Basics} allows you to get hold of an intermediate result (to do some |
502 side-calculations for instance). The function |
507 side-calculations for instance). The function |
503 *} |
508 *} |
504 |
509 |
508 |> (fn x => x + 2)*} |
513 |> (fn x => x + 2)*} |
509 |
514 |
510 text {* |
515 text {* |
511 increments the argument first by @{text "1"} and then by @{text "2"}. In the |
516 increments the argument first by @{text "1"} and then by @{text "2"}. In the |
512 middle (Line 3), however, it uses @{ML tap} for printing the ``plus-one'' |
517 middle (Line 3), however, it uses @{ML tap} for printing the ``plus-one'' |
513 intermediate result inside the tracing buffer. The function @{ML tap} can |
518 intermediate result. The function @{ML tap} can only be used for |
514 only be used for side-calculations, because any value that is computed |
519 side-calculations, because any value that is computed cannot be merged back |
515 cannot be merged back into the ``main waterfall''. To do this, you can use |
520 into the ``main waterfall''. To do this, you can use the next combinator. |
516 the next combinator. |
|
517 |
521 |
518 The combinator @{ML_ind "`" in Basics} (a backtick) is similar to @{ML tap}, |
522 The combinator @{ML_ind "`" in Basics} (a backtick) is similar to @{ML tap}, |
519 but applies a function to the value and returns the result together with the |
523 but applies a function to the value and returns the result together with the |
520 value (as a pair). For example the function |
524 value (as a pair). It is defined as |
|
525 *} |
|
526 |
|
527 ML{*fun `f = fn x => (f x, x)*} |
|
528 |
|
529 text {* |
|
530 An example for this combinator is the function |
521 *} |
531 *} |
522 |
532 |
523 ML{*fun inc_as_pair x = |
533 ML{*fun inc_as_pair x = |
524 x |> `(fn x => x + 1) |
534 x |> `(fn x => x + 1) |
525 |> (fn (x, y) => (x, y + 1))*} |
535 |> (fn (x, y) => (x, y + 1))*} |
526 |
536 |
527 text {* |
537 text {* |
528 takes @{text x} as argument, and then increments @{text x}, but also keeps |
538 which takes @{text x} as argument, and then increments @{text x}, but also keeps |
529 @{text x}. The intermediate result is therefore the pair @{ML "(x + 1, x)" |
539 @{text x}. The intermediate result is therefore the pair @{ML "(x + 1, x)" |
530 for x}. After that, the function increments the right-hand component of the |
540 for x}. After that, the function increments the right-hand component of the |
531 pair. So finally the result will be @{ML "(x + 1, x + 1)" for x}. |
541 pair. So finally the result will be @{ML "(x + 1, x + 1)" for x}. |
532 |
542 |
533 The combinators @{ML_ind "|>>" in Basics} and @{ML_ind "||>" in Basics} are |
543 The combinators @{ML_ind "|>>" in Basics} and @{ML_ind "||>" in Basics} are |
559 in |
569 in |
560 if i <= x then (los, x::grs) else (x::los, grs) |
570 if i <= x then (los, x::grs) else (x::los, grs) |
561 end*} |
571 end*} |
562 |
572 |
563 text {* |
573 text {* |
564 where however the return value of the recursive call is bound explicitly to |
574 where the return value of the recursive call is bound explicitly to |
565 the pair @{ML "(los, grs)" for los grs}. You can implement this function |
575 the pair @{ML "(los, grs)" for los grs}. You can implement this function |
566 more concisely as |
576 more concisely as |
567 *} |
577 *} |
568 |
578 |
569 ML{*fun separate i [] = ([], []) |
579 ML{*fun separate i [] = ([], []) |
643 text {* |
653 text {* |
644 When using combinators for writing functions in waterfall fashion, it is |
654 When using combinators for writing functions in waterfall fashion, it is |
645 sometimes necessary to do some ``plumbing'' in order to fit functions |
655 sometimes necessary to do some ``plumbing'' in order to fit functions |
646 together. We have already seen such plumbing in the function @{ML |
656 together. We have already seen such plumbing in the function @{ML |
647 apply_fresh_args}, where @{ML curry} is needed for making the function @{ML |
657 apply_fresh_args}, where @{ML curry} is needed for making the function @{ML |
648 list_comb} that works over pairs to fit with the combinator @{ML "|>"}. Such |
658 list_comb}, which works over pairs to fit with the combinator @{ML "|>"}. Such |
649 plumbing is also needed in situations where a function operate over lists, |
659 plumbing is also needed in situations where a function operate over lists, |
650 but one calculates only with a single element. An example is the function |
660 but one calculates only with a single element. An example is the function |
651 @{ML_ind check_terms in Syntax}, whose purpose is to type-check a list |
661 @{ML_ind check_terms in Syntax}, whose purpose is to simultaneously type-check |
652 of terms. Consider the code: |
662 a list of terms. Consider the code: |
653 |
663 |
654 @{ML_response_fake [display, gray] |
664 @{ML_response_fake [display, gray] |
655 "let |
665 "let |
656 val ctxt = @{context} |
666 val ctxt = @{context} |
657 in |
667 in |
710 text parts of Isabelle and their purpose is to print logical entities inside |
720 text parts of Isabelle and their purpose is to print logical entities inside |
711 \LaTeX-documents. Document antiquotations are part of the user level and |
721 \LaTeX-documents. Document antiquotations are part of the user level and |
712 therefore we are not interested in them in this Tutorial, except in Appendix |
722 therefore we are not interested in them in this Tutorial, except in Appendix |
713 \ref{rec:docantiquotations} where we show how to implement your own document |
723 \ref{rec:docantiquotations} where we show how to implement your own document |
714 antiquotations.} For example, one can print out the name of the current |
724 antiquotations.} For example, one can print out the name of the current |
715 theory by typing |
725 theory with the code |
716 |
726 |
717 @{ML_response [display,gray] "Context.theory_name @{theory}" "\"FirstSteps\""} |
727 @{ML_response [display,gray] "Context.theory_name @{theory}" "\"FirstSteps\""} |
718 |
728 |
719 where @{text "@{theory}"} is an antiquotation that is substituted with the |
729 where @{text "@{theory}"} is an antiquotation that is substituted with the |
720 current theory (remember that we assumed we are inside the theory |
730 current theory (remember that we assumed we are inside the theory |
775 @{ML_response_fake [display,gray] |
785 @{ML_response_fake [display,gray] |
776 "get_thm_names_from_ss @{simpset}" |
786 "get_thm_names_from_ss @{simpset}" |
777 "[\"Nat.of_nat_eq_id\", \"Int.of_int_eq_id\", \"Nat.One_nat_def\", \<dots>]"} |
787 "[\"Nat.of_nat_eq_id\", \"Int.of_int_eq_id\", \"Nat.One_nat_def\", \<dots>]"} |
778 |
788 |
779 Again, this way of referencing simpsets makes you independent from additions |
789 Again, this way of referencing simpsets makes you independent from additions |
780 of lemmas to the simpset by the user that can potentially cause loops in your |
790 of lemmas to the simpset by the user, which can potentially cause loops in your |
781 code. |
791 code. |
782 |
792 |
783 On the ML-level of Isabelle, you often have to work with qualified names. |
793 On the ML-level of Isabelle, you often have to work with qualified names. |
784 These are strings with some additional information, such as positional |
794 These are strings with some additional information, such as positional |
785 information and qualifiers. Such qualified names can be generated with the |
795 information and qualifiers. Such qualified names can be generated with the |
818 \footnote{\bf FIXME: There should probably a separate section on binding, long-names |
828 \footnote{\bf FIXME: There should probably a separate section on binding, long-names |
819 and sign.} |
829 and sign.} |
820 |
830 |
821 It is also possible to define your own antiquotations. But you should |
831 It is also possible to define your own antiquotations. But you should |
822 exercise care when introducing new ones, as they can also make your code |
832 exercise care when introducing new ones, as they can also make your code |
823 also difficult to read. In the next chapter we will see how the (build in) |
833 also difficult to read. In the next chapter we describe how the (build in) |
824 antiquotation @{text "@{term \<dots>}"} can be used to construct terms. A |
834 antiquotation @{text "@{term \<dots>}"} for constructing terms. A |
825 restriction of this antiquotation is that it does not allow you to use |
835 restriction of this antiquotation is that it does not allow you to use |
826 schematic variables. If you want to have an antiquotation that does not have |
836 schematic variables in terms. If you want to have an antiquotation that does not have |
827 this restriction, you can implement your own using the function @{ML_ind |
837 this restriction, you can implement your own using the function @{ML_ind |
828 inline in ML_Antiquote}. The code for the antiquotation @{text "term_pat"} is |
838 inline in ML_Antiquote} in the structure @{ML_struct ML_Antiquote}. The code |
829 as follows. |
839 for the antiquotation @{text "term_pat"} is as follows. |
830 *} |
840 *} |
831 |
841 |
832 ML %linenosgray{*let |
842 ML %linenosgray{*let |
833 val parser = Args.context -- Scan.lift Args.name_source |
843 val parser = Args.context -- Scan.lift Args.name_source |
834 |
844 |
842 |
852 |
843 text {* |
853 text {* |
844 The parser in Line 2 provides us with a context and a string; this string is |
854 The parser in Line 2 provides us with a context and a string; this string is |
845 transformed into a term using the function @{ML_ind read_term_pattern in |
855 transformed into a term using the function @{ML_ind read_term_pattern in |
846 ProofContext} (Line 5); the next two lines transform the term into a string |
856 ProofContext} (Line 5); the next two lines transform the term into a string |
847 so that the ML-system can understand it. An example for the usage |
857 so that the ML-system can understand it. An example for this antiquotation is: |
848 of this antiquotation is: |
|
849 |
858 |
850 @{ML_response_fake [display,gray] |
859 @{ML_response_fake [display,gray] |
851 "@{term_pat \"Suc (?x::nat)\"}" |
860 "@{term_pat \"Suc (?x::nat)\"}" |
852 "Const (\"Suc\", \"nat \<Rightarrow> nat\") $ Var ((\"x\", 0), \"nat\")"} |
861 "Const (\"Suc\", \"nat \<Rightarrow> nat\") $ Var ((\"x\", 0), \"nat\")"} |
853 |
862 |
854 which shows the internal representation of the term @{text "Suc ?x"}. |
863 which shows the internal representation of the term @{text "Suc ?x"}. |
855 This is different from the build-in @{text "@{term \<dots>}"}-antiquotation. |
|
856 |
|
857 @{ML_response_fake [display,gray] |
|
858 "@{term \"Suc (x::nat)\"}" |
|
859 "Const (\"Suc\", \"nat \<Rightarrow> nat\") $ Free (\"x\", \"nat\")"} |
|
860 |
864 |
861 \begin{readmore} |
865 \begin{readmore} |
862 The file @{ML_file "Pure/ML/ml_antiquote.ML"} contains the the definitions |
866 The file @{ML_file "Pure/ML/ml_antiquote.ML"} contains the the definitions |
863 for most antiquotations. Most of the basic operations on ML-syntax are implemented |
867 for most antiquotations. Most of the basic operations on ML-syntax are implemented |
864 in @{ML_file "Pure/ML/ml_syntax.ML"}. |
868 in @{ML_file "Pure/ML/ml_syntax.ML"}. |
868 section {* Storing Data in Isabelle\label{sec:storing} *} |
872 section {* Storing Data in Isabelle\label{sec:storing} *} |
869 |
873 |
870 text {* |
874 text {* |
871 Isabelle provides mechanisms for storing (and retrieving) arbitrary |
875 Isabelle provides mechanisms for storing (and retrieving) arbitrary |
872 data. Before we delve into the details, let us digress a bit. Conventional |
876 data. Before we delve into the details, let us digress a bit. Conventional |
873 wisdom has it that the type-system of ML ensures that for example an |
877 wisdom has it that the type-system of ML ensures that an |
874 @{ML_type "'a list"} can only hold elements of the same type, namely |
878 @{ML_type "'a list"}, say, can only hold elements of the same type, namely |
875 @{ML_type "'a"}. Despite this wisdom, however, it is possible to implement a |
879 @{ML_type "'a"}. Despite this wisdom, however, it is possible to implement a |
876 universal type in ML, although by some arguably accidental features of ML. |
880 universal type in ML, although by some arguably accidental features of ML. |
877 This universal type can be used to store data of different type into a single list. |
881 This universal type can be used to store data of different type into a single list. |
878 It allows one to inject and to project data of \emph{arbitrary} type. This is |
882 In fact, it allows one to inject and to project data of \emph{arbitrary} type. This is |
879 in contrast to datatypes, which only allow injection and projection of data for |
883 in contrast to datatypes, which only allow injection and projection of data for |
880 some fixed collection of types. In light of the conventional wisdom cited |
884 some fixed collection of types. In light of the conventional wisdom cited |
881 above it is important to keep in mind that the universal type does not |
885 above it is important to keep in mind that the universal type does not |
882 destroy type-safety of ML: storing and accessing the data can only be done |
886 destroy type-safety of ML: storing and accessing the data can only be done |
883 in a type-safe manner. |
887 in a type-safe manner. |
888 @{ML_file "Pure/ML-Systems/universal.ML"}. |
892 @{ML_file "Pure/ML-Systems/universal.ML"}. |
889 \end{readmore} |
893 \end{readmore} |
890 |
894 |
891 We will show the usage of the universal type by storing an integer and |
895 We will show the usage of the universal type by storing an integer and |
892 a boolean into a single list. Let us first define injection and projection |
896 a boolean into a single list. Let us first define injection and projection |
893 functions for booleans and integers into and from @{ML_type Universal.universal}. |
897 functions for booleans and integers into and from the type @{ML_type Universal.universal}. |
894 *} |
898 *} |
895 |
899 |
896 ML{*local |
900 ML{*local |
897 val fn_int = Universal.tag () : int Universal.tag |
901 val fn_int = Universal.tag () : int Universal.tag |
898 val fn_bool = Universal.tag () : bool Universal.tag |
902 val fn_bool = Universal.tag () : bool Universal.tag |
935 This runtime error is the reason why ML is still type-sound despite |
939 This runtime error is the reason why ML is still type-sound despite |
936 containing a universal type. |
940 containing a universal type. |
937 |
941 |
938 Now, Isabelle heavily uses this mechanism for storing all sorts of |
942 Now, Isabelle heavily uses this mechanism for storing all sorts of |
939 data: theorem lists, simpsets, facts etc. Roughly speaking, there are two |
943 data: theorem lists, simpsets, facts etc. Roughly speaking, there are two |
940 places where data can be stored: in \emph{theories} and in \emph{proof |
944 places where data can be stored in Isabelle: in \emph{theories} and in \emph{proof |
941 contexts}. Again roughly speaking, data such as simpsets need to be stored |
945 contexts}. Data such as simpsets need to be stored |
942 in a theory, since they need to be maintained across proofs and even across |
946 in a theory, since they need to be maintained across proofs and even across |
943 theories. On the other hand, data such as facts change inside a proof and |
947 theories. On the other hand, data such as facts change inside a proof and |
944 are only relevant to the proof at hand. Therefore such data needs to be |
948 are only relevant to the proof at hand. Therefore such data needs to be |
945 maintained inside a proof context.\footnote{\bf TODO: explain more about |
949 maintained inside a proof context. |
946 this in a separate section.} |
|
947 |
950 |
948 For theories and proof contexts there are, respectively, the functors |
951 For theories and proof contexts there are, respectively, the functors |
949 @{ML_funct_ind TheoryDataFun} and @{ML_funct_ind ProofDataFun} that help |
952 @{ML_funct_ind TheoryDataFun} and @{ML_funct_ind ProofDataFun} that help |
950 with the data storage. Below we show how to implement a table in which we |
953 with the data storage. Below we show how to implement a table in which we |
951 can store theorems and look them up according to a string key. The |
954 can store theorems and look them up according to a string key. The |
952 intention is to be able to look up introduction rules for logical |
955 intention in this example is to be able to look up introduction rules for logical |
953 connectives. Such a table might be useful in an automatic proof procedure |
956 connectives. Such a table might be useful in an automatic proof procedure |
954 and therefore it makes sense to store this data inside a theory. The code |
957 and therefore it makes sense to store this data inside a theory. |
955 for the table is: |
958 Therefore we use the functor @{ML_funct TheoryDataFun}. |
|
959 The code for the table is: |
956 *} |
960 *} |
957 |
961 |
958 ML %linenosgray{*structure Data = TheoryDataFun |
962 ML %linenosgray{*structure Data = TheoryDataFun |
959 (type T = thm Symtab.table |
963 (type T = thm Symtab.table |
960 val empty = Symtab.empty |
964 val empty = Symtab.empty |
962 val extend = I |
966 val extend = I |
963 fun merge _ = Symtab.merge (K true))*} |
967 fun merge _ = Symtab.merge (K true))*} |
964 |
968 |
965 text {* |
969 text {* |
966 In order to store data in a theory, we have to specify the type of the data |
970 In order to store data in a theory, we have to specify the type of the data |
967 (Line 2). In this case we specify the type @{ML_type "thm Symtab.table"}, which |
971 (Line 2). In this case we specify the type @{ML_type "thm Symtab.table"}, |
968 stands for tables in which @{ML_type string}s can be looked up producing an associated |
972 which stands for a table in which @{ML_type string}s can be looked up |
969 @{ML_type thm}. We also have to specify four functions: how to initialise |
973 producing an associated @{ML_type thm}. We also have to specify four |
970 the data storage (Line 3), how to copy it (Line 4), how to extend it (Line |
974 functions to use this functor: namely how to initialise the data storage |
971 5) and how two tables should be merged (Line 6). These functions correspond |
975 (Line 3), how to copy it (Line 4), how to extend it (Line 5) and how two |
972 roughly to the operations performed on theories.\footnote{\bf FIXME: Say more |
976 tables should be merged (Line 6). These functions correspond roughly to the |
973 about the assumptions of these operations.} The result structure @{ML_text Data} |
977 operations performed on theories and we just give some sensible |
|
978 defaults\footnote{\bf FIXME: Say more about the |
|
979 assumptions of these operations.} The result structure @{ML_text Data} |
974 contains functions for accessing the table (@{ML Data.get}) and for updating |
980 contains functions for accessing the table (@{ML Data.get}) and for updating |
975 it (@{ML Data.map}). There are also two more functions (@{ML Data.init} and |
981 it (@{ML Data.map}). There are also two more functions (@{ML Data.init} and |
976 @{ML Data.put}), which however we ignore here. Below we define two auxiliary |
982 @{ML Data.put}), which however are not relevant here. Below we define two |
977 functions, which help us with accessing the table. |
983 auxiliary functions, which help us with accessing the table. |
978 *} |
984 *} |
979 |
985 |
980 ML{*val lookup = Symtab.lookup o Data.get |
986 ML{*val lookup = Symtab.lookup o Data.get |
981 fun update k v = Data.map (Symtab.update (k, v))*} |
987 fun update k v = Data.map (Symtab.update (k, v))*} |
982 |
988 |
991 update "All" @{thm allI} |
997 update "All" @{thm allI} |
992 *} |
998 *} |
993 |
999 |
994 text {* |
1000 text {* |
995 The use of the command \isacommand{setup} makes sure the table in the |
1001 The use of the command \isacommand{setup} makes sure the table in the |
996 \emph{current} theory is updated. The lookup can now be performed as |
1002 \emph{current} theory is updated (this is explained further in |
997 follows. |
1003 section~\ref{sec:theories}). The lookup can now be performed as follows. |
998 |
1004 |
999 @{ML_response_fake [display, gray] |
1005 @{ML_response_fake [display, gray] |
1000 "lookup @{theory} \"op &\"" |
1006 "lookup @{theory} \"op &\"" |
1001 "SOME \"\<lbrakk>?P; ?Q\<rbrakk> \<Longrightarrow> ?P \<and> ?Q\""} |
1007 "SOME \"\<lbrakk>?P; ?Q\<rbrakk> \<Longrightarrow> ?P \<and> ?Q\""} |
1002 |
1008 |
1006 *} |
1012 *} |
1007 |
1013 |
1008 setup %gray {* update "op &" @{thm TrueI} *} |
1014 setup %gray {* update "op &" @{thm TrueI} *} |
1009 |
1015 |
1010 text {* |
1016 text {* |
1011 and @{ML lookup} now produces the introduction rule for @{term "True"} |
1017 and accordingly, @{ML lookup} now produces the introduction rule for @{term "True"} |
1012 |
1018 |
1013 @{ML_response_fake [display, gray] |
1019 @{ML_response_fake [display, gray] |
1014 "lookup @{theory} \"op &\"" |
1020 "lookup @{theory} \"op &\"" |
1015 "SOME \"True\""} |
1021 "SOME \"True\""} |
1016 |
1022 |
1017 there are no references involved. This is one of the most fundamental |
1023 there are no references involved. This is one of the most fundamental |
1018 coding conventions for programming in Isabelle. References would |
1024 coding conventions for programming in Isabelle. References |
1019 interfere with the multithreaded execution model of Isabelle and also |
1025 interfere with the multithreaded execution model of Isabelle and also |
1020 defeat its undo-mechanism in proof scripts. For this consider the |
1026 defeat its undo-mechanism. To see the latter, consider the |
1021 following data container where we maintain a reference to a list of |
1027 following data container where we maintain a reference to a list of |
1022 integers. |
1028 integers. |
1023 *} |
1029 *} |
1024 |
1030 |
1025 ML{*structure WrongRefData = TheoryDataFun |
1031 ML{*structure WrongRefData = TheoryDataFun |
1058 @{ML_response_fake [display,gray] |
1064 @{ML_response_fake [display,gray] |
1059 "WrongRefData.get @{theory}" |
1065 "WrongRefData.get @{theory}" |
1060 "ref [1]"} |
1066 "ref [1]"} |
1061 |
1067 |
1062 So far everything is as expected. But, the trouble starts if we attempt to |
1068 So far everything is as expected. But, the trouble starts if we attempt to |
1063 backtrack to the point ``before'' the \isacommand{setup}-command. There, we |
1069 backtrack to the ``point'' before the \isacommand{setup}-command. There, we |
1064 would expect that the list is empty again. But since it is stored in a |
1070 would expect that the list is empty again. But since it is stored in a |
1065 reference, Isabelle has no control over it. So it is not empty, but still |
1071 reference, Isabelle has no control over it. So it is not empty, but still |
1066 @{ML "ref [1]" in Unsynchronized}. Adding to the trouble, if we execute the |
1072 @{ML "ref [1]" in Unsynchronized}. Adding to the trouble, if we execute the |
1067 \isacommand{setup}-command again, we do not obtain @{ML "ref [1]" in |
1073 \isacommand{setup}-command again, we do not obtain @{ML "ref [1]" in |
1068 Unsynchronized}, but |
1074 Unsynchronized}, but |
1082 including association lists in @{ML_file "Pure/General/alist.ML"}, |
1088 including association lists in @{ML_file "Pure/General/alist.ML"}, |
1083 directed graphs in @{ML_file "Pure/General/graph.ML"}, and |
1089 directed graphs in @{ML_file "Pure/General/graph.ML"}, and |
1084 tables and symtables in @{ML_file "Pure/General/table.ML"}. |
1090 tables and symtables in @{ML_file "Pure/General/table.ML"}. |
1085 \end{readmore} |
1091 \end{readmore} |
1086 |
1092 |
1087 Storing data in a proof context is done in a similar fashion. The |
1093 Storing data in a proof context is done in a similar fashion. As mentioned |
1088 corresponding functor is @{ML_funct_ind ProofDataFun}. With the |
1094 before, the corresponding functor is @{ML_funct_ind ProofDataFun}. With the |
1089 following code we can store a list of terms in a proof context. |
1095 following code we can store a list of terms in a proof context. |
1090 *} |
1096 *} |
1091 |
1097 |
1092 ML{*structure Data = ProofDataFun |
1098 ML{*structure Data = ProofDataFun |
1093 (type T = term list |
1099 (type T = term list |
1094 fun init _ = [])*} |
1100 fun init _ = [])*} |
1095 |
1101 |
1096 text {* |
1102 text {* |
1097 The function we have to specify has to produce a list once a context |
1103 The function we have to specify has to produce a list once a context |
1098 is initialised (taking the theory into account from which the |
1104 is initialised (possibly taking the theory into account from which the |
1099 context is derived). We choose to just return the empty list. Next |
1105 context is derived). We choose to just return the empty list. Next |
1100 we define two auxiliary functions for updating the list with a given |
1106 we define two auxiliary functions for updating the list with a given |
1101 term and printing the list. |
1107 term and printing the list. |
1102 *} |
1108 *} |
1103 |
1109 |
1138 associated data. This is different to theories, where the command |
1144 associated data. This is different to theories, where the command |
1139 \isacommand{setup} registers the data with the current and future |
1145 \isacommand{setup} registers the data with the current and future |
1140 theories, and therefore one can access the data potentially |
1146 theories, and therefore one can access the data potentially |
1141 indefinitely. |
1147 indefinitely. |
1142 |
1148 |
1143 For convenience there is an abstract layer, the type @{ML_type Context.generic}, |
1149 For convenience there is an abstract layer, namely the type @{ML_type Context.generic}, |
1144 for theories and proof contexts. This type is defined as follows |
1150 for treating theories and proof contexts more uniformly. This type is defined as follows |
1145 *} |
1151 *} |
1146 |
1152 |
1147 ML_val{*datatype generic = |
1153 ML_val{*datatype generic = |
1148 Theory of theory |
1154 Theory of theory |
1149 | Proof of proof*} |
1155 | Proof of proof*} |
1150 |
1156 |
1151 text {* |
1157 text {* |
1152 For this type a number of operations are defined which allow the |
1158 \footnote{\bf FIXME: say more about generic contexts.} |
1153 uniform treatment of theories and proof contexts. |
|
1154 |
1159 |
1155 There are two special instances of the data storage mechanism described |
1160 There are two special instances of the data storage mechanism described |
1156 above. The first instance are named theorem lists. Since storing theorems in a list |
1161 above. The first instance implements named theorem lists using the functor |
1157 is such a common task, there is the special functor @{ML_funct_ind Named_Thms}. |
1162 @{ML_funct_ind Named_Thms}. This is because storing theorems in a list |
1158 To obtain a named theorem list, you just declare |
1163 is such a common task. To obtain a named theorem list, you just declare |
1159 *} |
1164 *} |
1160 |
1165 |
1161 ML{*structure FooRules = Named_Thms |
1166 ML{*structure FooRules = Named_Thms |
1162 (val name = "foo" |
1167 (val name = "foo" |
1163 val description = "Theorems for foo") *} |
1168 val description = "Theorems for foo") *} |
1171 text {* |
1176 text {* |
1172 This code declares a data container where the theorems are stored, |
1177 This code declares a data container where the theorems are stored, |
1173 an attribute @{text foo} (with the @{text add} and @{text del} options |
1178 an attribute @{text foo} (with the @{text add} and @{text del} options |
1174 for adding and deleting theorems) and an internal ML-interface to retrieve and |
1179 for adding and deleting theorems) and an internal ML-interface to retrieve and |
1175 modify the theorems. |
1180 modify the theorems. |
1176 |
1181 Furthermore, the theorems are made available on the user-level under the name |
1177 Furthermore, the facts are made available on the user-level under the dynamic |
1182 @{text foo}. For example you can declare three lemmas to be a member of the |
1178 fact name @{text foo}. For example you can declare three lemmas to be of the kind |
1183 theorem list @{text foo} by: |
1179 @{text foo} by: |
|
1180 *} |
1184 *} |
1181 |
1185 |
1182 lemma rule1[foo]: "A" sorry |
1186 lemma rule1[foo]: "A" sorry |
1183 lemma rule2[foo]: "B" sorry |
1187 lemma rule2[foo]: "B" sorry |
1184 lemma rule3[foo]: "C" sorry |
1188 lemma rule3[foo]: "C" sorry |
1185 |
1189 |
1186 text {* and undeclare the first one by: *} |
1190 text {* and undeclare the first one by: *} |
1187 |
1191 |
1188 declare rule1[foo del] |
1192 declare rule1[foo del] |
1189 |
1193 |
1190 text {* and query the remaining ones with: |
1194 text {* You can query the remaining ones with: |
1191 |
1195 |
1192 \begin{isabelle} |
1196 \begin{isabelle} |
1193 \isacommand{thm}~@{text "foo"}\\ |
1197 \isacommand{thm}~@{text "foo"}\\ |
1194 @{text "> ?C"}\\ |
1198 @{text "> ?C"}\\ |
1195 @{text "> ?B"} |
1199 @{text "> ?B"} |
1207 @{ML_response_fake [display,gray] |
1211 @{ML_response_fake [display,gray] |
1208 "FooRules.get @{context}" |
1212 "FooRules.get @{context}" |
1209 "[\"True\", \"?C\",\"?B\"]"} |
1213 "[\"True\", \"?C\",\"?B\"]"} |
1210 |
1214 |
1211 Note that this function takes a proof context as argument. This might be |
1215 Note that this function takes a proof context as argument. This might be |
1212 confusing, since the theorem list is stored as theory data. The proof context |
1216 confusing, since the theorem list is stored as theory data. It becomes clear by knowing |
1213 however conatains the information about the current theory and so the function |
1217 that the proof context contains the information about the current theory and so the function |
1214 can access the theorem list in the theory via the context. |
1218 can access the theorem list in the theory via the context. |
1215 |
1219 |
1216 \begin{readmore} |
1220 \begin{readmore} |
1217 For more information about named theorem lists see |
1221 For more information about named theorem lists see |
1218 @{ML_file "Pure/Tools/named_thms.ML"}. |
1222 @{ML_file "Pure/Tools/named_thms.ML"}. |
1270 "let |
1274 "let |
1271 val ctxt = @{context} |
1275 val ctxt = @{context} |
1272 val ctxt' = Config.put sval \"foo\" ctxt |
1276 val ctxt' = Config.put sval \"foo\" ctxt |
1273 val ctxt'' = Config.put sval \"bar\" ctxt' |
1277 val ctxt'' = Config.put sval \"bar\" ctxt' |
1274 in |
1278 in |
1275 (Config.get ctxt sval, Config.get ctxt' sval, Config.get ctxt'' sval) |
1279 (Config.get ctxt sval, |
|
1280 Config.get ctxt' sval, |
|
1281 Config.get ctxt'' sval) |
1276 end" |
1282 end" |
1277 "(\"some string\", \"foo\", \"bar\")"} |
1283 "(\"some string\", \"foo\", \"bar\")"} |
1278 |
1284 |
1279 \begin{readmore} |
1285 \begin{readmore} |
1280 For more information about configuration values see |
1286 For more information about configuration values see |