139 |
139 |
140 ML{*fun str_of_cterm ctxt t = |
140 ML{*fun str_of_cterm ctxt t = |
141 Syntax.string_of_term ctxt (term_of t)*} |
141 Syntax.string_of_term ctxt (term_of t)*} |
142 |
142 |
143 text {* |
143 text {* |
144 The function @{ML term_of} extracts the @{ML_type term} from a @{ML_type cterm}. |
144 In this example the function @{ML term_of} extracts the @{ML_type term} from |
145 If there are more than one @{ML_type cterm}s to be printed, you can use the |
145 a @{ML_type cterm}. If there are more than one @{ML_type cterm}s to be |
146 function @{ML commas} to separate them. |
146 printed, you can use the function @{ML commas} to separate them. |
147 *} |
147 *} |
148 |
148 |
149 ML{*fun str_of_cterms ctxt ts = |
149 ML{*fun str_of_cterms ctxt ts = |
150 commas (map (str_of_cterm ctxt) ts)*} |
150 commas (map (str_of_cterm ctxt) ts)*} |
151 |
151 |
212 the first component of the pair (Line 4) and finally incrementing the first |
212 the first component of the pair (Line 4) and finally incrementing the first |
213 component by 4 (Line 5). This kind of cascading manipulations of values is quite |
213 component by 4 (Line 5). This kind of cascading manipulations of values is quite |
214 common when dealing with theories (for example by adding a definition, followed by |
214 common when dealing with theories (for example by adding a definition, followed by |
215 lemmas and so on). The reverse application allows you to read what happens in |
215 lemmas and so on). The reverse application allows you to read what happens in |
216 a top-down manner. This kind of coding should also be familiar, |
216 a top-down manner. This kind of coding should also be familiar, |
217 if you used to Haskell's do-notation. Writing the function @{ML inc_by_five} using |
217 if you have been exposed to Haskell's do-notation. Writing the function @{ML inc_by_five} using |
218 the reverse application is much clearer than writing |
218 the reverse application is much clearer than writing |
219 *} |
219 *} |
220 |
220 |
221 ML{*fun inc_by_five x = fst ((fn x => (x, x)) (x + 1)) + 4*} |
221 ML{*fun inc_by_five x = fst ((fn x => (x, x)) (x + 1)) + 4*} |
222 |
222 |
387 @{ML_response_fake [display,gray] "@{thms conj_ac}" |
387 @{ML_response_fake [display,gray] "@{thms conj_ac}" |
388 "(?P \<and> ?Q) = (?Q \<and> ?P) |
388 "(?P \<and> ?Q) = (?Q \<and> ?P) |
389 (?P \<and> ?Q \<and> ?R) = (?Q \<and> ?P \<and> ?R) |
389 (?P \<and> ?Q \<and> ?R) = (?Q \<and> ?P \<and> ?R) |
390 ((?P \<and> ?Q) \<and> ?R) = (?P \<and> ?Q \<and> ?R)"} |
390 ((?P \<and> ?Q) \<and> ?R) = (?P \<and> ?Q \<and> ?R)"} |
391 |
391 |
392 You can also refer to the current simpset. To illustrate this we use the |
392 You can also refer to the current simpset. To illustrate this we implement the |
393 function that extracts the theorem names stored in a simpset. |
393 function that extracts the theorem names stored in a simpset. |
394 *} |
394 *} |
395 |
395 |
396 ML{*fun get_thm_names simpset = |
396 ML{*fun get_thm_names_from_ss simpset = |
397 let |
397 let |
398 val ({rules,...}, _) = MetaSimplifier.rep_ss simpset |
398 val ({rules,...}, _) = MetaSimplifier.rep_ss simpset |
399 in |
399 in |
400 map #name (Net.entries rules) |
400 map #name (Net.entries rules) |
401 end*} |
401 end*} |
403 text {* |
403 text {* |
404 The function @{ML rep_ss in MetaSimplifier} returns a record containing all |
404 The function @{ML rep_ss in MetaSimplifier} returns a record containing all |
405 information about the simpset. The rules of a simpset are stored in a |
405 information about the simpset. The rules of a simpset are stored in a |
406 \emph{discrimination net} (a data structure for fast indexing). From this |
406 \emph{discrimination net} (a data structure for fast indexing). From this |
407 net you can extract the entries using the function @{ML Net.entries}. |
407 net you can extract the entries using the function @{ML Net.entries}. |
408 You can now use @{ML get_thm_names} to obtain all names of theorems stored |
408 You can now use @{ML get_thm_names_from_ss} to obtain all names of theorems stored |
409 in the current simpset---this simpset can be referred to using the antiquotation |
409 in the current simpset---this simpset can be referred to using the antiquotation |
410 @{text "@{simpset}"}.\footnote |
410 @{text "@{simpset}"}. |
411 {FIXME: you cannot cleanly match against lists with ommited parts} |
|
412 |
411 |
413 @{ML_response_fake [display,gray] |
412 @{ML_response_fake [display,gray] |
414 "get_thm_names @{simpset}" "[\"Nat.of_nat_eq_id\", \"Int.of_int_eq_id\", \"Nat.One_nat_def\", \<dots>]"} |
413 "get_thm_names_from_ss @{simpset}" |
|
414 "[\"Nat.of_nat_eq_id\", \"Int.of_int_eq_id\", \"Nat.One_nat_def\", \<dots>]"} |
415 |
415 |
416 \begin{readmore} |
416 \begin{readmore} |
417 The infrastructure for simpsets is implemented in @{ML_file "Pure/meta_simplifier.ML"} |
417 The infrastructure for simpsets is implemented in @{ML_file "Pure/meta_simplifier.ML"} |
418 and @{ML_file "Pure/simplifier.ML"}. Discrimination nets are implemented |
418 and @{ML_file "Pure/simplifier.ML"}. Discrimination nets are implemented |
419 in @{ML_file "Pure/net.ML"}. |
419 in @{ML_file "Pure/net.ML"}. |
429 These bindings are difficult to maintain and also can be accidentally |
429 These bindings are difficult to maintain and also can be accidentally |
430 overwritten by the user. This often breakes Isabelle |
430 overwritten by the user. This often breakes Isabelle |
431 packages. Antiquotations solve this problem, since they are ``linked'' |
431 packages. Antiquotations solve this problem, since they are ``linked'' |
432 statically at compile-time. However, this static linkage also limits their |
432 statically at compile-time. However, this static linkage also limits their |
433 usefulness in cases where data needs to be build up dynamically. In the |
433 usefulness in cases where data needs to be build up dynamically. In the |
434 course of this introduction, you will learn more about these antiquotations: |
434 course of this chapter you will learn more about these antiquotations: |
435 they can simplify Isabelle programming since one can directly access all |
435 they can simplify Isabelle programming since one can directly access all |
436 kinds of logical elements from th ML-level. |
436 kinds of logical elements from th ML-level. |
437 |
437 |
438 *} |
438 *} |
439 |
439 |
444 \mbox{@{text "@{term \<dots>}"}}. For example: |
444 \mbox{@{text "@{term \<dots>}"}}. For example: |
445 |
445 |
446 @{ML_response [display,gray] |
446 @{ML_response [display,gray] |
447 "@{term \"(a::nat) + b = c\"}" |
447 "@{term \"(a::nat) + b = c\"}" |
448 "Const (\"op =\", \<dots>) $ |
448 "Const (\"op =\", \<dots>) $ |
449 (Const (\"HOL.plus_class.plus\", \<dots>) $ \<dots> $ \<dots>) $ \<dots>"} |
449 (Const (\"HOL.plus_class.plus\", \<dots>) $ \<dots> $ \<dots>) $ \<dots>"} |
450 |
450 |
451 This will show the term @{term "(a::nat) + b = c"}, but printed using the internal |
451 This will show the term @{term "(a::nat) + b = c"}, but printed using the internal |
452 representation of this term. This internal representation corresponds to the |
452 representation of this term. This internal representation corresponds to the |
453 datatype @{ML_type "term"}. |
453 datatype @{ML_type "term"}. |
454 |
454 |
455 The internal representation of terms uses the usual de Bruijn index mechanism where bound |
455 The internal representation of terms uses the usual de Bruijn index mechanism where bound |
456 variables are represented by the constructor @{ML Bound}. The index in @{ML Bound} refers to |
456 variables are represented by the constructor @{ML Bound}. The index in @{ML Bound} refers to |
457 the number of Abstractions (@{ML Abs}) we have to skip until we hit the @{ML Abs} that |
457 the number of Abstractions (@{ML Abs}) we have to skip until we hit the @{ML Abs} that |
458 binds the corresponding variable. However, in Isabelle the names of bound variables are |
458 binds the corresponding variable. However, in Isabelle the names of bound variables are |
459 kept at abstractions for printing purposes, and so should be treated only as comments. |
459 kept at abstractions for printing purposes, and so should be treated only as ``comments''. |
460 Application in Isabelle is realised with the term-constructor @{ML $}. |
460 Application in Isabelle is realised with the term-constructor @{ML $}. |
461 |
461 |
462 \begin{readmore} |
462 \begin{readmore} |
463 Terms are described in detail in \isccite{sec:terms}. Their |
463 Terms are described in detail in \isccite{sec:terms}. Their |
464 definition and many useful operations are implemented in @{ML_file "Pure/term.ML"}. |
464 definition and many useful operations are implemented in @{ML_file "Pure/term.ML"}. |
490 inserting the invisible @{text "Trueprop"}-coercions whenever necessary. |
490 inserting the invisible @{text "Trueprop"}-coercions whenever necessary. |
491 Consider for example the pairs |
491 Consider for example the pairs |
492 |
492 |
493 @{ML_response [display,gray] "(@{term \"P x\"}, @{prop \"P x\"})" |
493 @{ML_response [display,gray] "(@{term \"P x\"}, @{prop \"P x\"})" |
494 "(Free (\"P\", \<dots>) $ Free (\"x\", \<dots>), |
494 "(Free (\"P\", \<dots>) $ Free (\"x\", \<dots>), |
495 Const (\"Trueprop\", \<dots>) $ (Free (\"P\", \<dots>) $ Free (\"x\", \<dots>)))"} |
495 Const (\"Trueprop\", \<dots>) $ (Free (\"P\", \<dots>) $ Free (\"x\", \<dots>)))"} |
496 |
496 |
497 where a coercion is inserted in the second component and |
497 where a coercion is inserted in the second component and |
498 |
498 |
499 @{ML_response [display,gray] "(@{term \"P x \<Longrightarrow> Q x\"}, @{prop \"P x \<Longrightarrow> Q x\"})" |
499 @{ML_response [display,gray] "(@{term \"P x \<Longrightarrow> Q x\"}, @{prop \"P x \<Longrightarrow> Q x\"})" |
500 "(Const (\"==>\", \<dots>) $ \<dots> $ \<dots>, Const (\"==>\", \<dots>) $ \<dots> $ \<dots>)"} |
500 "(Const (\"==>\", \<dots>) $ \<dots> $ \<dots>, Const (\"==>\", \<dots>) $ \<dots> $ \<dots>)"} |
615 in unary notation (like @{term "Suc (Suc (Suc 0))"}), and produce the |
615 in unary notation (like @{term "Suc (Suc (Suc 0))"}), and produce the |
616 number representing their sum. |
616 number representing their sum. |
617 \end{exercise} |
617 \end{exercise} |
618 |
618 |
619 There are a few subtle issues with constants. They usually crop up when |
619 There are a few subtle issues with constants. They usually crop up when |
620 pattern matching terms or types, or constructing them. While it is perfectly ok |
620 pattern matching terms or types, or when constructing them. While it is perfectly ok |
621 to write the function @{text is_true} as follows |
621 to write the function @{text is_true} as follows |
622 *} |
622 *} |
623 |
623 |
624 ML{*fun is_true @{term True} = true |
624 ML{*fun is_true @{term True} = true |
625 | is_true _ = false*} |
625 | is_true _ = false*} |
664 Unfortunately, also this function does \emph{not} work as expected, since |
665 Unfortunately, also this function does \emph{not} work as expected, since |
665 |
666 |
666 @{ML_response [display,gray] "is_nil @{term \"Nil\"}" "false"} |
667 @{ML_response [display,gray] "is_nil @{term \"Nil\"}" "false"} |
667 |
668 |
668 The problem is that on the ML-level the name of a constant is more |
669 The problem is that on the ML-level the name of a constant is more |
669 subtle as you might expect. The function @{ML is_all} worked correctly, |
670 subtle than you might expect. The function @{ML is_all} worked correctly, |
670 because @{term "All"} is such a fundamental constant, which can be referenced |
671 because @{term "All"} is such a fundamental constant, which can be referenced |
671 by @{ML "Const (\"All\", some_type)" for some_type}. However, if you look at |
672 by @{ML "Const (\"All\", some_type)" for some_type}. However, if you look at |
672 |
673 |
673 @{ML_response [display,gray] "@{term \"Nil\"}" "Const (\"List.list.Nil\", \<dots>)"} |
674 @{ML_response [display,gray] "@{term \"Nil\"}" "Const (\"List.list.Nil\", \<dots>)"} |
674 |
675 |
730 |
731 |
731 Type-checking is always relative to a theory context. For now we use |
732 Type-checking is always relative to a theory context. For now we use |
732 the @{ML "@{theory}"} antiquotation to get hold of the current theory. |
733 the @{ML "@{theory}"} antiquotation to get hold of the current theory. |
733 For example you can write: |
734 For example you can write: |
734 |
735 |
735 @{ML_response_fake [display,gray] "cterm_of @{theory} @{term \"a + b = c\"}" "a + b = c"} |
736 @{ML_response_fake [display,gray] "cterm_of @{theory} @{term \"(a::nat) + b = c\"}" "a + b = c"} |
736 |
737 |
737 This can also be written with an antiquotation: |
738 This can also be written with an antiquotation: |
738 |
739 |
739 @{ML_response_fake [display,gray] "@{cterm \"(a::nat) + b = c\"}" "a + b = c"} |
740 @{ML_response_fake [display,gray] "@{cterm \"(a::nat) + b = c\"}" "a + b = c"} |
740 |
741 |
768 @{ML_response [display,gray] |
769 @{ML_response [display,gray] |
769 "type_of (@{term \"f::nat \<Rightarrow> bool\"} $ @{term \"x::nat\"})" "bool"} |
770 "type_of (@{term \"f::nat \<Rightarrow> bool\"} $ @{term \"x::nat\"})" "bool"} |
770 |
771 |
771 To calculate the type, this function traverses the whole term and will |
772 To calculate the type, this function traverses the whole term and will |
772 detect any typing inconsistency. For examle changing the type of the variable |
773 detect any typing inconsistency. For examle changing the type of the variable |
773 from @{typ "nat"} to @{typ "int"} will result in the error message: |
774 @{term "x"} from @{typ "nat"} to @{typ "int"} will result in the error message: |
774 |
775 |
775 @{ML_response_fake [display,gray] |
776 @{ML_response_fake [display,gray] |
776 "type_of (@{term \"f::nat \<Rightarrow> bool\"} $ @{term \"x::int\"})" |
777 "type_of (@{term \"f::nat \<Rightarrow> bool\"} $ @{term \"x::int\"})" |
777 "*** Exception- TYPE (\"type_of: type mismatch in application\" \<dots>"} |
778 "*** Exception- TYPE (\"type_of: type mismatch in application\" \<dots>"} |
778 |
779 |
779 Since the complete traversal might sometimes be too costly and |
780 Since the complete traversal might sometimes be too costly and |
780 not necessary, there is also the function @{ML fastype_of}, which |
781 not necessary, there is the function @{ML fastype_of}, which |
781 returns the type of a term. |
782 also returns the type of a term. |
782 |
783 |
783 @{ML_response [display,gray] |
784 @{ML_response [display,gray] |
784 "fastype_of (@{term \"f::nat \<Rightarrow> bool\"} $ @{term \"x::nat\"})" "bool"} |
785 "fastype_of (@{term \"f::nat \<Rightarrow> bool\"} $ @{term \"x::nat\"})" "bool"} |
785 |
786 |
786 However, efficiency is gained on the expense of skiping some tests. You |
787 However, efficiency is gained on the expense of skiping some tests. You |
787 can see this in the following example |
788 can see this in the following example |
788 |
789 |
789 @{ML_response [display,gray] |
790 @{ML_response [display,gray] |
790 "fastype_of (@{term \"f::nat \<Rightarrow> bool\"} $ @{term \"x::int\"})" "bool"} |
791 "fastype_of (@{term \"f::nat \<Rightarrow> bool\"} $ @{term \"x::int\"})" "bool"} |
791 |
792 |
792 where no error is raised. |
793 where no error is detected. |
793 |
794 |
794 Sometimes it is a bit inconvenient to construct a term with |
795 Sometimes it is a bit inconvenient to construct a term with |
795 complete typing annotations, especially in cases where the typing |
796 complete typing annotations, especially in cases where the typing |
796 information is redundant. A short-cut is to use the ``place-holder'' |
797 information is redundant. A short-cut is to use the ``place-holder'' |
797 type @{ML "dummyT"} and then let type-inference figure out the |
798 type @{ML "dummyT"} and then let type-inference figure out the |
807 end" |
808 end" |
808 "Const (\"HOL.plus_class.plus\", \"nat \<Rightarrow> nat \<Rightarrow> nat\") $ |
809 "Const (\"HOL.plus_class.plus\", \"nat \<Rightarrow> nat \<Rightarrow> nat\") $ |
809 Const (\"HOL.one_class.one\", \"nat\") $ Free (\"x\", \"nat\")"} |
810 Const (\"HOL.one_class.one\", \"nat\") $ Free (\"x\", \"nat\")"} |
810 |
811 |
811 Instead of giving explicitly the type for the constant @{text "plus"} and the free |
812 Instead of giving explicitly the type for the constant @{text "plus"} and the free |
812 variable @{text "x"}, the type-inference filled in the missing information. |
813 variable @{text "x"}, the type-inference filles in the missing information. |
813 |
814 |
814 \begin{readmore} |
815 \begin{readmore} |
815 See @{ML_file "Pure/Syntax/syntax.ML"} where more functions about reading, |
816 See @{ML_file "Pure/Syntax/syntax.ML"} where more functions about reading, |
816 checking and pretty-printing of terms are defined. |
817 checking and pretty-printing of terms are defined. |
817 \end{readmore} |
818 \end{readmore} |
840 The corresponding ML-code is as follows:\footnote{Note that @{text "|>"} is reverse |
841 The corresponding ML-code is as follows:\footnote{Note that @{text "|>"} is reverse |
841 application. See Section~\ref{sec:combinators}.} |
842 application. See Section~\ref{sec:combinators}.} |
842 |
843 |
843 @{ML_response_fake [display,gray] |
844 @{ML_response_fake [display,gray] |
844 "let |
845 "let |
845 |
|
846 val assm1 = @{cprop \"\<And>(x::nat). P x \<Longrightarrow> Q x\"} |
846 val assm1 = @{cprop \"\<And>(x::nat). P x \<Longrightarrow> Q x\"} |
847 val assm2 = @{cprop \"(P::nat\<Rightarrow>bool) t\"} |
847 val assm2 = @{cprop \"(P::nat\<Rightarrow>bool) t\"} |
848 |
848 |
849 val Pt_implies_Qt = |
849 val Pt_implies_Qt = |
850 assume assm1 |
850 assume assm1 |
914 |
914 |
915 ML{*val my_symmetric = Thm.rule_attribute (fn _ => fn thm => thm RS @{thm sym})*} |
915 ML{*val my_symmetric = Thm.rule_attribute (fn _ => fn thm => thm RS @{thm sym})*} |
916 |
916 |
917 text {* |
917 text {* |
918 where the function @{ML "Thm.rule_attribute"} expects a function taking a |
918 where the function @{ML "Thm.rule_attribute"} expects a function taking a |
919 context (we ignore it in the code above) and a theorem (@{text thm}) and |
919 context (which we ignore in the code above) and a theorem (@{text thm}), and |
920 returns another theorem (namely @{text thm} resolved with the rule |
920 returns another theorem (namely @{text thm} resolved with the lemma |
921 @{thm sym[no_vars]}). The function @{ML "Thm.rule_attribute"} then returns |
921 @{thm [source] sym}: @{thm sym[no_vars]}). The function @{ML "Thm.rule_attribute"} then returns |
922 an attribute (of type @{ML_type "attribute"}). |
922 an attribute (of type @{ML_type "attribute"}). |
923 |
923 |
924 Before we can use the attribute, we need to set it up. This can be done |
924 Before we can use the attribute, we need to set it up. This can be done |
925 using the function @{ML Attrib.add_attributes} as follows. |
925 using the function @{ML Attrib.add_attributes} as follows. |
926 *} |
926 *} |
929 Attrib.add_attributes |
929 Attrib.add_attributes |
930 [("my_sym", Attrib.no_args my_symmetric, "applying the sym rule")] |
930 [("my_sym", Attrib.no_args my_symmetric, "applying the sym rule")] |
931 *} |
931 *} |
932 |
932 |
933 text {* |
933 text {* |
934 The attribute does not expect any further arguments (like @{text "[OF \<dots>]"} that |
934 The attribute does not expect any further arguments (unlike @{text "[OF |
935 can take a list of theorems as argument). Therefore we use the function |
935 \<dots>]"}, for example, which can take a list of theorems as argument). Therefore |
936 @{ML Attrib.no_args}. Later on we will also consider attributes taking further |
936 we use the function @{ML Attrib.no_args}. Later on we will also consider |
937 arguments. An example for the attribute @{text "[my_sym]"} is the proof |
937 attributes taking further arguments. An example for the attribute @{text |
|
938 "[my_sym]"} is the proof |
938 *} |
939 *} |
939 |
940 |
940 lemma test[my_sym]: "2 = Suc (Suc 0)" by simp |
941 lemma test[my_sym]: "2 = Suc (Suc 0)" by simp |
941 |
942 |
942 text {* |
943 text {* |