264 text {* |
264 text {* |
265 The easiest way to get the string of a theorem is to transform it |
265 The easiest way to get the string of a theorem is to transform it |
266 into a @{ML_type term} using the function @{ML_ind prop_of}. |
266 into a @{ML_type term} using the function @{ML_ind prop_of}. |
267 *} |
267 *} |
268 |
268 |
269 ML {* Thm.rep_thm @{thm mp} *} |
|
270 |
|
271 ML{*fun string_of_thm ctxt thm = |
269 ML{*fun string_of_thm ctxt thm = |
272 Syntax.string_of_term ctxt (prop_of thm)*} |
270 string_of_term ctxt (prop_of thm)*} |
273 |
271 |
274 text {* |
272 text {* |
275 Theorems also include schematic variables, such as @{text "?P"}, |
273 Theorems also include schematic variables, such as @{text "?P"}, |
276 @{text "?Q"} and so on. They are needed in order to able to |
274 @{text "?Q"} and so on. They are needed in order to able to |
277 instantiate theorems when they are applied. For example the theorem |
275 instantiate theorems when they are applied. For example the theorem |
636 sometimes necessary to do some ``plumbing'' in order to fit functions |
634 sometimes necessary to do some ``plumbing'' in order to fit functions |
637 together. We have already seen such plumbing in the function @{ML |
635 together. We have already seen such plumbing in the function @{ML |
638 apply_fresh_args}, where @{ML curry} is needed for making the function @{ML |
636 apply_fresh_args}, where @{ML curry} is needed for making the function @{ML |
639 list_comb} that works over pairs to fit with the combinator @{ML "|>"}. Such |
637 list_comb} that works over pairs to fit with the combinator @{ML "|>"}. Such |
640 plumbing is also needed in situations where a functions operate over lists, |
638 plumbing is also needed in situations where a functions operate over lists, |
641 but one calculates only with a single entity. An example is the function |
639 but one calculates only with a single element. An example is the function |
642 @{ML_ind check_terms in Syntax}, whose purpose is to type-check a list |
640 @{ML_ind check_terms in Syntax}, whose purpose is to type-check a list |
643 of terms. |
641 of terms. |
644 |
642 |
645 @{ML_response_fake [display, gray] |
643 @{ML_response_fake [display, gray] |
646 "let |
644 "let |
653 end" |
651 end" |
654 "m + n, m * n, m - n"} |
652 "m + n, m * n, m - n"} |
655 *} |
653 *} |
656 |
654 |
657 text {* |
655 text {* |
658 In this example we obtain three terms where @{text m} and @{text n} are of |
656 In this example we obtain three terms in which @{text m} and @{text n} are of |
659 type @{typ "nat"}. However, if you have only a single term, then @{ML |
657 type @{typ "nat"}. If you have only a single term, then @{ML |
660 check_terms in Syntax} needs plumbing. This can be done with the function |
658 check_terms in Syntax} needs plumbing. This can be done with the function |
661 @{ML singleton}.\footnote{There is already a function @{ML check_term in |
659 @{ML singleton}.\footnote{There is already a function @{ML check_term in |
662 Syntax} in the Isabelle sources that is defined in terms of @{ML singleton} |
660 Syntax} in the Isabelle sources that is defined in terms of @{ML singleton} |
663 and @{ML check_terms in Syntax}.} For example |
661 and @{ML check_terms in Syntax}.} For example |
664 |
662 |
690 |
688 |
691 text {* |
689 text {* |
692 The main advantage of embedding all code in a theory is that the code can |
690 The main advantage of embedding all code in a theory is that the code can |
693 contain references to entities defined on the logical level of Isabelle. By |
691 contain references to entities defined on the logical level of Isabelle. By |
694 this we mean definitions, theorems, terms and so on. This kind of reference |
692 this we mean definitions, theorems, terms and so on. This kind of reference |
695 is realised with ML-antiquotations, often just called |
693 is realised in Isabelle with ML-antiquotations, often just called |
696 antiquotations.\footnote{There are two kinds of antiquotations in Isabelle, |
694 antiquotations.\footnote{There are two kinds of antiquotations in Isabelle, |
697 which have very different purpose and infrastructures. The first kind, |
695 which have very different purposes and infrastructures. The first kind, |
698 described in this section, are \emph{ML-antiquotations}. They are used to |
696 described in this section, are \emph{ML-antiquotations}. They are used to |
699 refer to entities (like terms, types etc) from Isabelle's logic layer inside |
697 refer to entities (like terms, types etc) from Isabelle's logic layer inside |
700 ML-code. The other kind of antiquotations are \emph{document} |
698 ML-code. The other kind of antiquotations are \emph{document} |
701 antiquotations. They are used only in the text parts of Isabelle and their |
699 antiquotations. They are used only in the text parts of Isabelle and their |
702 purpose is to print logical entities inside \LaTeX-documents. They are part |
700 purpose is to print logical entities inside \LaTeX-documents. Document |
703 of the user level and therefore we are not interested in them in this |
701 antiquotations are part of the user level and therefore we are not |
704 Tutorial, except in Appendix \ref{rec:docantiquotations} where we show how |
702 interested in them in this Tutorial, except in Appendix |
705 to implement your own document antiquotations.} For example, one can print |
703 \ref{rec:docantiquotations} where we show how to implement your own document |
706 out the name of the current theory by typing |
704 antiquotations.} For example, one can print out the name of the current |
|
705 theory by typing |
|
706 |
707 |
707 |
708 @{ML_response [display,gray] "Context.theory_name @{theory}" "\"FirstSteps\""} |
708 @{ML_response [display,gray] "Context.theory_name @{theory}" "\"FirstSteps\""} |
709 |
709 |
710 where @{text "@{theory}"} is an antiquotation that is substituted with the |
710 where @{text "@{theory}"} is an antiquotation that is substituted with the |
711 current theory (remember that we assumed we are inside the theory |
711 current theory (remember that we assumed we are inside the theory |
784 @{ML_ind define in LocalTheory}. This function is used below to define |
784 @{ML_ind define in LocalTheory}. This function is used below to define |
785 the constant @{term "TrueConj"} as the conjunction @{term "True \<and> True"}. |
785 the constant @{term "TrueConj"} as the conjunction @{term "True \<and> True"}. |
786 *} |
786 *} |
787 |
787 |
788 local_setup %gray {* |
788 local_setup %gray {* |
789 snd o LocalTheory.define Thm.internalK |
789 LocalTheory.define Thm.internalK |
790 ((@{binding "TrueConj"}, NoSyn), |
790 ((@{binding "TrueConj"}, NoSyn), |
791 (Attrib.empty_binding, @{term "True \<and> True"})) *} |
791 (Attrib.empty_binding, @{term "True \<and> True"})) #> snd *} |
792 |
792 |
793 text {* |
793 text {* |
794 Now querying the definition you obtain: |
794 Now querying the definition you obtain: |
795 |
795 |
796 \begin{isabelle} |
796 \begin{isabelle} |
811 this restriction, you can implement your own using the function @{ML_ind |
811 this restriction, you can implement your own using the function @{ML_ind |
812 ML_Antiquote.inline}. The code for the antiquotation @{text "term_pat"} is |
812 ML_Antiquote.inline}. The code for the antiquotation @{text "term_pat"} is |
813 as follows. |
813 as follows. |
814 *} |
814 *} |
815 |
815 |
816 ML %linenosgray{*ML_Antiquote.inline "term_pat" |
816 ML %linenosgray{*let |
817 (Args.context -- Scan.lift Args.name_source >> |
817 val parser = Args.context -- Scan.lift Args.name_source |
818 (fn (ctxt, s) => |
818 |
819 s |> ProofContext.read_term_pattern ctxt |
819 fun term_pat (ctxt, str) = |
|
820 str |> ProofContext.read_term_pattern ctxt |
820 |> ML_Syntax.print_term |
821 |> ML_Syntax.print_term |
821 |> ML_Syntax.atomic))*} |
822 |> ML_Syntax.atomic |
|
823 in |
|
824 ML_Antiquote.inline "term_pat" (parser >> term_pat) |
|
825 end*} |
822 |
826 |
823 text {* |
827 text {* |
824 The parser in Line 2 provides us with a context and a string; this string is |
828 The parser in Line 2 provides us with a context and a string; this string is |
825 transformed into a term using the function @{ML_ind read_term_pattern in |
829 transformed into a term using the function @{ML_ind read_term_pattern in |
826 ProofContext} (Line 4); the next two lines transform the term into a string |
830 ProofContext} (Line 5); the next two lines transform the term into a string |
827 so that the ML-system can understand them. The function @{ML_ind atomic in |
831 so that the ML-system can understand them. An example for the usage |
828 ML_Syntax} just encloses the term in parentheses. An example for the usage |
|
829 of this antiquotation is: |
832 of this antiquotation is: |
830 |
833 |
831 @{ML_response_fake [display,gray] |
834 @{ML_response_fake [display,gray] |
832 "@{term_pat \"Suc (?x::nat)\"}" |
835 "@{term_pat \"Suc (?x::nat)\"}" |
833 "Const (\"Suc\", \"nat \<Rightarrow> nat\") $ Var ((\"x\", 0), \"nat\")"} |
836 "Const (\"Suc\", \"nat \<Rightarrow> nat\") $ Var ((\"x\", 0), \"nat\")"} |
839 for most antiquotations. Most of the basic operations on ML-syntax are implemented |
842 for most antiquotations. Most of the basic operations on ML-syntax are implemented |
840 in @{ML_file "Pure/ML/ml_syntax.ML"}. |
843 in @{ML_file "Pure/ML/ml_syntax.ML"}. |
841 \end{readmore} |
844 \end{readmore} |
842 *} |
845 *} |
843 |
846 |
844 section {* Storing Data (TBD) *} |
847 section {* Storing Data in Isabelle (TBD) *} |
845 |
848 |
846 text {* |
849 text {* |
847 Isabelle provides a mechanism to store (and retrieve) arbitrary data. Before we |
850 Isabelle provides mechanisms to store (and retrieve) arbitrary data. Before we |
848 explain this mechanism, let us digress a bit. Convenitional wisdom is that the |
851 explain them, let us digress: Convenitional wisdom has it that |
849 type-system of ML ensures that for example an @{ML_type "'a list"} can only |
852 ML's type-system ensures that for example an @{ML_type "'a list"} can only |
850 hold elements of type @{ML_type "'a"}. |
853 hold elements of the same type, namely @{ML_type "'a"}. Still, by some arguably |
851 *} |
854 accidental features of ML, one can implement a universal type. In Isabelle it |
852 |
855 is implemented as @{ML_type Universal.universal}. This type allows one to |
853 ML{*signature UNIVERSAL_TYPE = |
856 inject and project elements of different type into for example into a list. |
854 sig |
857 We will show this by storing an integer and boolean in a list. What is important |
855 type t |
858 that access to the data is done in a type-safe manner. |
856 |
859 |
857 val embed: unit -> ('a -> t) * (t -> 'a option) |
860 Let us first define projection and injection functions for booleans and integers. |
|
861 *} |
|
862 |
|
863 ML{*local |
|
864 val fn_int = Universal.tag () : int Universal.tag |
|
865 val fn_bool = Universal.tag () : bool Universal.tag |
|
866 in |
|
867 val inject_int = Universal.tagInject fn_int; |
|
868 val inject_bool = Universal.tagInject fn_bool; |
|
869 val project_int = Universal.tagProject fn_int; |
|
870 val project_bool = Universal.tagProject fn_bool |
858 end*} |
871 end*} |
859 |
872 |
860 ML{*structure U:> UNIVERSAL_TYPE = |
873 text {* |
861 struct |
874 We can now build a list injecting @{ML_text "13"} and @{ML_text "true"} as |
862 type t = exn |
875 its two elements. |
863 |
876 *} |
864 fun 'a embed () = |
877 |
865 let |
878 ML{* val list = [inject_int 13, inject_bool true]*} |
866 exception E of 'a |
879 |
867 fun project (e: t): 'a option = |
880 ML {* |
868 case e of |
881 project_int (nth list 0) |
869 E a => SOME a |
882 *} |
870 | _ => NONE |
883 |
871 in |
884 ML {* |
872 (E, project) |
885 project_bool (nth list 1) |
873 end |
886 *} |
874 end*} |
887 |
875 |
888 (**************************************************) |
876 text {* |
889 (* bak *) |
877 The idea is that type t is the universal type and that each call to embed |
890 (**************************************************) |
878 returns a new pair of functions (inject, project), where inject embeds a |
|
879 value into the universal type and project extracts the value from the |
|
880 universal type. A pair (inject, project) returned by embed works together in |
|
881 that project u will return SOME v if and only if u was created by inject |
|
882 v. If u was created by a different function inject', then project returns |
|
883 NONE. |
|
884 |
|
885 in library.ML |
|
886 *} |
|
887 |
|
888 ML_val{*structure Object = struct type T = exn end; *} |
|
889 |
|
890 ML{*functor Test (U: UNIVERSAL_TYPE): sig end = |
|
891 struct |
|
892 val (intIn: int -> U.t, intOut) = U.embed () |
|
893 val r: U.t ref = ref (intIn 13) |
|
894 val s1 = |
|
895 case intOut (!r) of |
|
896 NONE => "NONE" |
|
897 | SOME i => Int.toString i |
|
898 val (realIn: real -> U.t, realOut) = U.embed () |
|
899 val _ = r := realIn 13.0 |
|
900 val s2 = |
|
901 case intOut (!r) of |
|
902 NONE => "NONE" |
|
903 | SOME i => Int.toString i |
|
904 val s3 = |
|
905 case realOut (!r) of |
|
906 NONE => "NONE" |
|
907 | SOME x => Real.toString x |
|
908 val _ = tracing (implode [s1, " ", s2, " ", s3, "\n"]) |
|
909 end*} |
|
910 |
|
911 ML_val{*structure t = Test(U) *} |
|
912 |
|
913 ML_val{*structure Datatab = Table(type key = int val ord = int_ord);*} |
|
914 |
|
915 ML {* LocalTheory.restore *} |
|
916 ML {* LocalTheory.set_group *} |
|
917 |
|
918 |
|
919 |
891 |
920 (* |
892 (* |
921 section {* Do Not Try This At Home! *} |
893 section {* Do Not Try This At Home! *} |
922 |
894 |
923 ML {* val my_thms = ref ([]: thm list) *} |
895 ML {* val my_thms = ref ([]: thm list) *} |