46 |
46 |
47 text \<open> |
47 text \<open> |
48 This proof translates to the following ML-code. |
48 This proof translates to the following ML-code. |
49 |
49 |
50 @{ML_matchresult_fake [display,gray] |
50 @{ML_matchresult_fake [display,gray] |
51 "let |
51 \<open>let |
52 val ctxt = @{context} |
52 val ctxt = @{context} |
53 val goal = @{prop \"P \<or> Q \<Longrightarrow> Q \<or> P\"} |
53 val goal = @{prop "P \<or> Q \<Longrightarrow> Q \<or> P"} |
54 in |
54 in |
55 Goal.prove ctxt [\"P\", \"Q\"] [] goal |
55 Goal.prove ctxt ["P", "Q"] [] goal |
56 (fn _ => eresolve_tac @{context} [@{thm disjE}] 1 |
56 (fn _ => eresolve_tac @{context} [@{thm disjE}] 1 |
57 THEN resolve_tac @{context} [@{thm disjI2}] 1 |
57 THEN resolve_tac @{context} [@{thm disjI2}] 1 |
58 THEN assume_tac @{context} 1 |
58 THEN assume_tac @{context} 1 |
59 THEN resolve_tac @{context} [@{thm disjI1}] 1 |
59 THEN resolve_tac @{context} [@{thm disjI1}] 1 |
60 THEN assume_tac @{context} 1) |
60 THEN assume_tac @{context} 1) |
61 end" "?P \<or> ?Q \<Longrightarrow> ?Q \<or> ?P"} |
61 end\<close> \<open>?P \<or> ?Q \<Longrightarrow> ?Q \<or> ?P\<close>} |
62 |
62 |
63 To start the proof, the function @{ML_ind prove in Goal} sets up a goal |
63 To start the proof, the function @{ML_ind prove in Goal} sets up a goal |
64 state for proving the goal @{prop "P \<or> Q \<Longrightarrow> Q \<or> P"}. We can give this |
64 state for proving the goal @{prop "P \<or> Q \<Longrightarrow> Q \<or> P"}. We can give this |
65 function some assumptions in the third argument (there are no assumption in |
65 function some assumptions in the third argument (there are no assumption in |
66 the proof at hand). The second argument stands for a list of variables |
66 the proof at hand). The second argument stands for a list of variables |
762 constrained version of the \<open>bspec\<close>-theorem. One way to give such |
762 constrained version of the \<open>bspec\<close>-theorem. One way to give such |
763 constraints is by pre-instantiating theorems with other theorems. |
763 constraints is by pre-instantiating theorems with other theorems. |
764 The function @{ML_ind RS in Drule}, for example, does this. |
764 The function @{ML_ind RS in Drule}, for example, does this. |
765 |
765 |
766 @{ML_matchresult_fake [display,gray] |
766 @{ML_matchresult_fake [display,gray] |
767 "@{thm disjI1} RS @{thm conjI}" "\<lbrakk>?P1; ?Q\<rbrakk> \<Longrightarrow> (?P1 \<or> ?Q1) \<and> ?Q"} |
767 \<open>@{thm disjI1} RS @{thm conjI}\<close> \<open>\<lbrakk>?P1; ?Q\<rbrakk> \<Longrightarrow> (?P1 \<or> ?Q1) \<and> ?Q\<close>} |
768 |
768 |
769 In this example it instantiates the first premise of the \<open>conjI\<close>-theorem |
769 In this example it instantiates the first premise of the \<open>conjI\<close>-theorem |
770 with the theorem \<open>disjI1\<close>. If the instantiation is impossible, as in the |
770 with the theorem \<open>disjI1\<close>. If the instantiation is impossible, as in the |
771 case of |
771 case of |
772 |
772 |
773 @{ML_matchresult_fake_both [display,gray] |
773 @{ML_matchresult_fake_both [display,gray] |
774 "@{thm conjI} RS @{thm mp}" |
774 \<open>@{thm conjI} RS @{thm mp}\<close> |
775 "*** Exception- THM (\"RSN: no unifiers\", 1, |
775 \<open>*** Exception- THM ("RSN: no unifiers", 1, |
776 [\"\<lbrakk>?P; ?Q\<rbrakk> \<Longrightarrow> ?P \<and> ?Q\", \"\<lbrakk>?P \<longrightarrow> ?Q; ?P\<rbrakk> \<Longrightarrow> ?Q\"]) raised"} |
776 ["\<lbrakk>?P; ?Q\<rbrakk> \<Longrightarrow> ?P \<and> ?Q", "\<lbrakk>?P \<longrightarrow> ?Q; ?P\<rbrakk> \<Longrightarrow> ?Q"]) raised\<close>} |
777 |
777 |
778 then the function raises an exception. The function @{ML_ind RSN in Drule} |
778 then the function raises an exception. The function @{ML_ind RSN in Drule} |
779 is similar to @{ML RS}, but takes an additional number as argument. This |
779 is similar to @{ML RS}, but takes an additional number as argument. This |
780 number makes explicit which premise should be instantiated. |
780 number makes explicit which premise should be instantiated. |
781 |
781 |
782 If you want to instantiate more than one premise of a theorem, you can use |
782 If you want to instantiate more than one premise of a theorem, you can use |
783 the function @{ML_ind MRS in Drule}: |
783 the function @{ML_ind MRS in Drule}: |
784 |
784 |
785 @{ML_matchresult_fake [display,gray] |
785 @{ML_matchresult_fake [display,gray] |
786 "[@{thm disjI1}, @{thm disjI2}] MRS @{thm conjI}" |
786 \<open>[@{thm disjI1}, @{thm disjI2}] MRS @{thm conjI}\<close> |
787 "\<lbrakk>?P2; ?Q1\<rbrakk> \<Longrightarrow> (?P2 \<or> ?Q2) \<and> (?P1 \<or> ?Q1)"} |
787 \<open>\<lbrakk>?P2; ?Q1\<rbrakk> \<Longrightarrow> (?P2 \<or> ?Q2) \<and> (?P1 \<or> ?Q1)\<close>} |
788 |
788 |
789 If you need to instantiate lists of theorems, you can use the |
789 If you need to instantiate lists of theorems, you can use the |
790 functions @{ML_ind RL in Drule} and @{ML_ind OF in Drule}. For |
790 functions @{ML_ind RL in Drule} and @{ML_ind OF in Drule}. For |
791 example in the code below, every theorem in the second list is |
791 example in the code below, every theorem in the second list is |
792 instantiated with every theorem in the first. |
792 instantiated with every theorem in the first. |
793 |
793 |
794 @{ML_matchresult_fake [display,gray] |
794 @{ML_matchresult_fake [display,gray] |
795 "let |
795 \<open>let |
796 val list1 = [@{thm impI}, @{thm disjI2}] |
796 val list1 = [@{thm impI}, @{thm disjI2}] |
797 val list2 = [@{thm conjI}, @{thm disjI1}] |
797 val list2 = [@{thm conjI}, @{thm disjI1}] |
798 in |
798 in |
799 list1 RL list2 |
799 list1 RL list2 |
800 end" |
800 end\<close> |
801 "[\<lbrakk>?P1 \<Longrightarrow> ?Q1; ?Q\<rbrakk> \<Longrightarrow> (?P1 \<longrightarrow> ?Q1) \<and> ?Q, |
801 \<open>[\<lbrakk>?P1 \<Longrightarrow> ?Q1; ?Q\<rbrakk> \<Longrightarrow> (?P1 \<longrightarrow> ?Q1) \<and> ?Q, |
802 \<lbrakk>?Q1; ?Q\<rbrakk> \<Longrightarrow> (?P1 \<or> ?Q1) \<and> ?Q, |
802 \<lbrakk>?Q1; ?Q\<rbrakk> \<Longrightarrow> (?P1 \<or> ?Q1) \<and> ?Q, |
803 (?P1 \<Longrightarrow> ?Q1) \<Longrightarrow> (?P1 \<longrightarrow> ?Q1) \<or> ?Q, |
803 (?P1 \<Longrightarrow> ?Q1) \<Longrightarrow> (?P1 \<longrightarrow> ?Q1) \<or> ?Q, |
804 ?Q1 \<Longrightarrow> (?P1 \<or> ?Q1) \<or> ?Q]"} |
804 ?Q1 \<Longrightarrow> (?P1 \<or> ?Q1) \<or> ?Q]\<close>} |
805 |
805 |
806 \begin{readmore} |
806 \begin{readmore} |
807 The combinators for instantiating theorems with other theorems are |
807 The combinators for instantiating theorems with other theorems are |
808 defined in @{ML_file "Pure/drule.ML"}. |
808 defined in @{ML_file "Pure/drule.ML"}. |
809 \end{readmore} |
809 \end{readmore} |
1095 TRY}, it does not fail anymore. The problem is that for the user there is |
1095 TRY}, it does not fail anymore. The problem is that for the user there is |
1096 little chance to see whether progress in the proof has been made, or not. By |
1096 little chance to see whether progress in the proof has been made, or not. By |
1097 convention therefore, tactics visible to the user should either change |
1097 convention therefore, tactics visible to the user should either change |
1098 something or fail. |
1098 something or fail. |
1099 |
1099 |
1100 To comply with this convention, we could simply delete the @{ML "K all_tac"} |
1100 To comply with this convention, we could simply delete the @{ML \<open>K all_tac\<close>} |
1101 in @{ML select_tac'} or delete @{ML TRY} from @{ML select_tac''}. But for |
1101 in @{ML select_tac'} or delete @{ML TRY} from @{ML select_tac''}. But for |
1102 the sake of argument, let us suppose that this deletion is \emph{not} an |
1102 the sake of argument, let us suppose that this deletion is \emph{not} an |
1103 option. In such cases, you can use the combinator @{ML_ind CHANGED in |
1103 option. In such cases, you can use the combinator @{ML_ind CHANGED in |
1104 Tactical} to make sure the subgoal has been changed by the tactic. Because |
1104 Tactical} to make sure the subgoal has been changed by the tactic. Because |
1105 now |
1105 now |
1457 To see how they work, consider the function in Figure~\ref{fig:printss}, which |
1457 To see how they work, consider the function in Figure~\ref{fig:printss}, which |
1458 prints out some parts of a simpset. If you use it to print out the components of the |
1458 prints out some parts of a simpset. If you use it to print out the components of the |
1459 empty simpset, i.e., @{ML_ind empty_ss in Raw_Simplifier} |
1459 empty simpset, i.e., @{ML_ind empty_ss in Raw_Simplifier} |
1460 |
1460 |
1461 @{ML_matchresult_fake [display,gray] |
1461 @{ML_matchresult_fake [display,gray] |
1462 "print_ss @{context} empty_ss" |
1462 \<open>print_ss @{context} empty_ss\<close> |
1463 "Simplification rules: |
1463 \<open>Simplification rules: |
1464 Congruences rules: |
1464 Congruences rules: |
1465 Simproc patterns:"} |
1465 Simproc patterns:\<close>} |
1466 |
1466 |
1467 you can see it contains nothing. This simpset is usually not useful, except as a |
1467 you can see it contains nothing. This simpset is usually not useful, except as a |
1468 building block to build bigger simpsets. For example you can add to @{ML empty_ss} |
1468 building block to build bigger simpsets. For example you can add to @{ML empty_ss} |
1469 the simplification rule @{thm [source] Diff_Int} as follows: |
1469 the simplification rule @{thm [source] Diff_Int} as follows: |
1470 \<close> |
1470 \<close> |
1490 |
1490 |
1491 text \<open> |
1491 text \<open> |
1492 gives |
1492 gives |
1493 |
1493 |
1494 @{ML_matchresult_fake [display,gray] |
1494 @{ML_matchresult_fake [display,gray] |
1495 "print_ss @{context} (Raw_Simplifier.simpset_of ss2)" |
1495 \<open>print_ss @{context} (Raw_Simplifier.simpset_of ss2)\<close> |
1496 "Simplification rules: |
1496 \<open>Simplification rules: |
1497 ??.unknown: A - B \<inter> C \<equiv> A - B \<union> (A - C) |
1497 ??.unknown: A - B \<inter> C \<equiv> A - B \<union> (A - C) |
1498 Congruences rules: |
1498 Congruences rules: |
1499 Complete_Lattices.Inf_class.INFIMUM: |
1499 Complete_Lattices.Inf_class.INFIMUM: |
1500 \<lbrakk>A1 = B1; \<And>x. x \<in> B1 =simp=> C1 x = D1 x\<rbrakk> \<Longrightarrow> INFIMUM A1 C1 \<equiv> INFIMUM B1 D1 |
1500 \<lbrakk>A1 = B1; \<And>x. x \<in> B1 =simp=> C1 x = D1 x\<rbrakk> \<Longrightarrow> INFIMUM A1 C1 \<equiv> INFIMUM B1 D1 |
1501 Simproc patterns:"} |
1501 Simproc patterns:\<close>} |
1502 |
1502 |
1503 Notice that we had to add these lemmas as meta-equations. The @{ML empty_ss} |
1503 Notice that we had to add these lemmas as meta-equations. The @{ML empty_ss} |
1504 expects this form of the simplification and congruence rules. This is |
1504 expects this form of the simplification and congruence rules. This is |
1505 different, if we use for example the simpset @{ML HOL_basic_ss} (see below), |
1505 different, if we use for example the simpset @{ML HOL_basic_ss} (see below), |
1506 where rules are usually added as equation. However, even |
1506 where rules are usually added as equation. However, even |
1507 when adding these lemmas to @{ML empty_ss} we do not end up with anything useful yet. |
1507 when adding these lemmas to @{ML empty_ss} we do not end up with anything useful yet. |
1508 In the context of HOL, the first really useful simpset is @{ML_ind |
1508 In the context of HOL, the first really useful simpset is @{ML_ind |
1509 HOL_basic_ss in Simpdata}. While printing out the components of this simpset |
1509 HOL_basic_ss in Simpdata}. While printing out the components of this simpset |
1510 |
1510 |
1511 @{ML_matchresult_fake [display,gray] |
1511 @{ML_matchresult_fake [display,gray] |
1512 "print_ss @{context} HOL_basic_ss" |
1512 \<open>print_ss @{context} HOL_basic_ss\<close> |
1513 "Simplification rules: |
1513 \<open>Simplification rules: |
1514 Congruences rules: |
1514 Congruences rules: |
1515 Simproc patterns:"} |
1515 Simproc patterns:\<close>} |
1516 |
1516 |
1517 also produces ``nothing'', the printout is somewhat misleading. In fact |
1517 also produces ``nothing'', the printout is somewhat misleading. In fact |
1518 the @{ML HOL_basic_ss} is setup so that it can solve goals of the |
1518 the @{ML HOL_basic_ss} is setup so that it can solve goals of the |
1519 form |
1519 form |
1520 |
1520 |
1541 The simpset @{ML_ind HOL_ss} is an extension of @{ML HOL_basic_ss} containing |
1541 The simpset @{ML_ind HOL_ss} is an extension of @{ML HOL_basic_ss} containing |
1542 already many useful simplification and congruence rules for the logical |
1542 already many useful simplification and congruence rules for the logical |
1543 connectives in HOL. |
1543 connectives in HOL. |
1544 |
1544 |
1545 @{ML_matchresult_fake [display,gray] |
1545 @{ML_matchresult_fake [display,gray] |
1546 "print_ss @{context} HOL_ss" |
1546 \<open>print_ss @{context} HOL_ss\<close> |
1547 "Simplification rules: |
1547 \<open>Simplification rules: |
1548 Pure.triv_forall_equality: (\<And>x. PROP V) \<equiv> PROP V |
1548 Pure.triv_forall_equality: (\<And>x. PROP V) \<equiv> PROP V |
1549 HOL.the_eq_trivial: THE x. x = y \<equiv> y |
1549 HOL.the_eq_trivial: THE x. x = y \<equiv> y |
1550 HOL.the_sym_eq_trivial: THE ya. y = ya \<equiv> y |
1550 HOL.the_sym_eq_trivial: THE ya. y = ya \<equiv> y |
1551 \<dots> |
1551 \<dots> |
1552 Congruences rules: |
1552 Congruences rules: |
1553 HOL.simp_implies: \<dots> |
1553 HOL.simp_implies: \<dots> |
1554 \<Longrightarrow> (PROP P =simp=> PROP Q) \<equiv> (PROP P' =simp=> PROP Q') |
1554 \<Longrightarrow> (PROP P =simp=> PROP Q) \<equiv> (PROP P' =simp=> PROP Q') |
1555 op -->: \<lbrakk>P \<equiv> P'; P' \<Longrightarrow> Q \<equiv> Q'\<rbrakk> \<Longrightarrow> P \<longrightarrow> Q \<equiv> P' \<longrightarrow> Q' |
1555 op -->: \<lbrakk>P \<equiv> P'; P' \<Longrightarrow> Q \<equiv> Q'\<rbrakk> \<Longrightarrow> P \<longrightarrow> Q \<equiv> P' \<longrightarrow> Q' |
1556 Simproc patterns: |
1556 Simproc patterns: |
1557 \<dots>"} |
1557 \<dots>\<close>} |
1558 |
1558 |
1559 \begin{readmore} |
1559 \begin{readmore} |
1560 The simplifier for HOL is set up in @{ML_file "HOL/Tools/simpdata.ML"}. |
1560 The simplifier for HOL is set up in @{ML_file "HOL/Tools/simpdata.ML"}. |
1561 The simpset @{ML HOL_ss} is implemented in @{ML_file "HOL/HOL.thy"}. |
1561 The simpset @{ML HOL_ss} is implemented in @{ML_file "HOL/HOL.thy"}. |
1562 \end{readmore} |
1562 \end{readmore} |
2063 whereby the produced theorem is always a meta-equality. A simple conversion |
2063 whereby the produced theorem is always a meta-equality. A simple conversion |
2064 is the function @{ML_ind all_conv in Conv}, which maps a @{ML_type cterm} to an |
2064 is the function @{ML_ind all_conv in Conv}, which maps a @{ML_type cterm} to an |
2065 instance of the (meta)reflexivity theorem. For example: |
2065 instance of the (meta)reflexivity theorem. For example: |
2066 |
2066 |
2067 @{ML_matchresult_fake [display,gray] |
2067 @{ML_matchresult_fake [display,gray] |
2068 "Conv.all_conv @{cterm \"Foo \<or> Bar\"}" |
2068 \<open>Conv.all_conv @{cterm "Foo \<or> Bar"}\<close> |
2069 "Foo \<or> Bar \<equiv> Foo \<or> Bar"} |
2069 \<open>Foo \<or> Bar \<equiv> Foo \<or> Bar\<close>} |
2070 |
2070 |
2071 Another simple conversion is @{ML_ind no_conv in Conv} which always raises the |
2071 Another simple conversion is @{ML_ind no_conv in Conv} which always raises the |
2072 exception @{ML CTERM}. |
2072 exception @{ML CTERM}. |
2073 |
2073 |
2074 @{ML_matchresult_fake [display,gray] |
2074 @{ML_matchresult_fake [display,gray] |
2075 "Conv.no_conv @{cterm True}" |
2075 \<open>Conv.no_conv @{cterm True}\<close> |
2076 "*** Exception- CTERM (\"no conversion\", []) raised"} |
2076 \<open>*** Exception- CTERM ("no conversion", []) raised\<close>} |
2077 |
2077 |
2078 A more interesting conversion is the function @{ML_ind beta_conversion in Thm}: it |
2078 A more interesting conversion is the function @{ML_ind beta_conversion in Thm}: it |
2079 produces a meta-equation between a term and its beta-normal form. For example |
2079 produces a meta-equation between a term and its beta-normal form. For example |
2080 |
2080 |
2081 @{ML_matchresult_fake [display,gray] |
2081 @{ML_matchresult_fake [display,gray] |
2082 "let |
2082 \<open>let |
2083 val add = @{cterm \"\<lambda>x y. x + (y::nat)\"} |
2083 val add = @{cterm "\<lambda>x y. x + (y::nat)"} |
2084 val two = @{cterm \"2::nat\"} |
2084 val two = @{cterm "2::nat"} |
2085 val ten = @{cterm \"10::nat\"} |
2085 val ten = @{cterm "10::nat"} |
2086 val ctrm = Thm.apply (Thm.apply add two) ten |
2086 val ctrm = Thm.apply (Thm.apply add two) ten |
2087 in |
2087 in |
2088 Thm.beta_conversion true ctrm |
2088 Thm.beta_conversion true ctrm |
2089 end" |
2089 end\<close> |
2090 "((\<lambda>x y. x + y) 2) 10 \<equiv> 2 + 10"} |
2090 \<open>((\<lambda>x y. x + y) 2) 10 \<equiv> 2 + 10\<close>} |
2091 |
2091 |
2092 If you run this example, you will notice that the actual response is the |
2092 If you run this example, you will notice that the actual response is the |
2093 seemingly nonsensical @{term |
2093 seemingly nonsensical @{term |
2094 "2 + 10 \<equiv> 2 + (10::nat)"}. The reason is that the pretty-printer for |
2094 "2 + 10 \<equiv> 2 + (10::nat)"}. The reason is that the pretty-printer for |
2095 @{ML_type cterm}s eta-normalises (sic) terms and therefore produces this output. |
2095 @{ML_type cterm}s eta-normalises (sic) terms and therefore produces this output. |
2096 If we get hold of the ``raw'' representation of the produced theorem, |
2096 If we get hold of the ``raw'' representation of the produced theorem, |
2097 we obtain the expected result. |
2097 we obtain the expected result. |
2098 |
2098 |
2099 @{ML_matchresult [display,gray] |
2099 @{ML_matchresult [display,gray] |
2100 "let |
2100 \<open>let |
2101 val add = @{cterm \"\<lambda>x y. x + (y::nat)\"} |
2101 val add = @{cterm "\<lambda>x y. x + (y::nat)"} |
2102 val two = @{cterm \"2::nat\"} |
2102 val two = @{cterm "2::nat"} |
2103 val ten = @{cterm \"10::nat\"} |
2103 val ten = @{cterm "10::nat"} |
2104 val ctrm = Thm.apply (Thm.apply add two) ten |
2104 val ctrm = Thm.apply (Thm.apply add two) ten |
2105 in |
2105 in |
2106 Thm.prop_of (Thm.beta_conversion true ctrm) |
2106 Thm.prop_of (Thm.beta_conversion true ctrm) |
2107 end" |
2107 end\<close> |
2108 "Const (\"Pure.eq\",_) $ |
2108 \<open>Const ("Pure.eq",_) $ |
2109 (Abs (\"x\",_,Abs (\"y\",_,_)) $_$_) $ |
2109 (Abs ("x",_,Abs ("y",_,_)) $_$_) $ |
2110 (Const (\"Groups.plus_class.plus\",_) $ _ $ _)"} |
2110 (Const ("Groups.plus_class.plus",_) $ _ $ _)\<close>} |
2111 |
2111 |
2112 or in the pretty-printed form |
2112 or in the pretty-printed form |
2113 |
2113 |
2114 @{ML_matchresult_fake [display,gray] |
2114 @{ML_matchresult_fake [display,gray] |
2115 "let |
2115 \<open>let |
2116 val add = @{cterm \"\<lambda>x y. x + (y::nat)\"} |
2116 val add = @{cterm "\<lambda>x y. x + (y::nat)"} |
2117 val two = @{cterm \"2::nat\"} |
2117 val two = @{cterm "2::nat"} |
2118 val ten = @{cterm \"10::nat\"} |
2118 val ten = @{cterm "10::nat"} |
2119 val ctrm = Thm.apply (Thm.apply add two) ten |
2119 val ctrm = Thm.apply (Thm.apply add two) ten |
2120 val ctxt = @{context} |
2120 val ctxt = @{context} |
2121 |> Config.put eta_contract false |
2121 |> Config.put eta_contract false |
2122 |> Config.put show_abbrevs false |
2122 |> Config.put show_abbrevs false |
2123 in |
2123 in |
2124 Thm.prop_of (Thm.beta_conversion true ctrm) |
2124 Thm.prop_of (Thm.beta_conversion true ctrm) |
2125 |> pretty_term ctxt |
2125 |> pretty_term ctxt |
2126 |> pwriteln |
2126 |> pwriteln |
2127 end" |
2127 end\<close> |
2128 "(\<lambda>x y. x + y) 2 10 \<equiv> 2 + 10"} |
2128 \<open>(\<lambda>x y. x + y) 2 10 \<equiv> 2 + 10\<close>} |
2129 |
2129 |
2130 The argument @{ML true} in @{ML beta_conversion in Thm} indicates that |
2130 The argument @{ML true} in @{ML beta_conversion in Thm} indicates that |
2131 the right-hand side should be fully beta-normalised. If instead |
2131 the right-hand side should be fully beta-normalised. If instead |
2132 @{ML false} is given, then only a single beta-reduction is performed |
2132 @{ML false} is given, then only a single beta-reduction is performed |
2133 on the outer-most level. |
2133 on the outer-most level. |
2145 text \<open> |
2145 text \<open> |
2146 It can be used for example to rewrite @{term "True \<and> (Foo \<longrightarrow> Bar)"} |
2146 It can be used for example to rewrite @{term "True \<and> (Foo \<longrightarrow> Bar)"} |
2147 to @{term "Foo \<longrightarrow> Bar"}. The code is as follows. |
2147 to @{term "Foo \<longrightarrow> Bar"}. The code is as follows. |
2148 |
2148 |
2149 @{ML_matchresult_fake [display,gray] |
2149 @{ML_matchresult_fake [display,gray] |
2150 "let |
2150 \<open>let |
2151 val ctrm = @{cterm \"True \<and> (Foo \<longrightarrow> Bar)\"} |
2151 val ctrm = @{cterm "True \<and> (Foo \<longrightarrow> Bar)"} |
2152 in |
2152 in |
2153 Conv.rewr_conv @{thm true_conj1} ctrm |
2153 Conv.rewr_conv @{thm true_conj1} ctrm |
2154 end" |
2154 end\<close> |
2155 "True \<and> (Foo \<longrightarrow> Bar) \<equiv> Foo \<longrightarrow> Bar"} |
2155 \<open>True \<and> (Foo \<longrightarrow> Bar) \<equiv> Foo \<longrightarrow> Bar\<close>} |
2156 |
2156 |
2157 Note, however, that the function @{ML_ind rewr_conv in Conv} only rewrites the |
2157 Note, however, that the function @{ML_ind rewr_conv in Conv} only rewrites the |
2158 outer-most level of the @{ML_type cterm}. If the given @{ML_type cterm} does not match |
2158 outer-most level of the @{ML_type cterm}. If the given @{ML_type cterm} does not match |
2159 exactly the |
2159 exactly the |
2160 left-hand side of the theorem, then @{ML_ind rewr_conv in Conv} fails, raising |
2160 left-hand side of the theorem, then @{ML_ind rewr_conv in Conv} fails, raising |
2164 combining several conversions into one. For this you can use conversion |
2164 combining several conversions into one. For this you can use conversion |
2165 combinators. The simplest conversion combinator is @{ML_ind then_conv in Conv}, |
2165 combinators. The simplest conversion combinator is @{ML_ind then_conv in Conv}, |
2166 which applies one conversion after another. For example |
2166 which applies one conversion after another. For example |
2167 |
2167 |
2168 @{ML_matchresult_fake [display,gray] |
2168 @{ML_matchresult_fake [display,gray] |
2169 "let |
2169 \<open>let |
2170 val conv1 = Thm.beta_conversion false |
2170 val conv1 = Thm.beta_conversion false |
2171 val conv2 = Conv.rewr_conv @{thm true_conj1} |
2171 val conv2 = Conv.rewr_conv @{thm true_conj1} |
2172 val ctrm = Thm.apply @{cterm \"\<lambda>x. x \<and> False\"} @{cterm \"True\"} |
2172 val ctrm = Thm.apply @{cterm "\<lambda>x. x \<and> False"} @{cterm "True"} |
2173 in |
2173 in |
2174 (conv1 then_conv conv2) ctrm |
2174 (conv1 then_conv conv2) ctrm |
2175 end" |
2175 end\<close> |
2176 "(\<lambda>x. x \<and> False) True \<equiv> False"} |
2176 \<open>(\<lambda>x. x \<and> False) True \<equiv> False\<close>} |
2177 |
2177 |
2178 where we first beta-reduce the term and then rewrite according to |
2178 where we first beta-reduce the term and then rewrite according to |
2179 @{thm [source] true_conj1}. (When running this example recall the |
2179 @{thm [source] true_conj1}. (When running this example recall the |
2180 problem with the pretty-printer normalising all terms.) |
2180 problem with the pretty-printer normalising all terms.) |
2181 |
2181 |
2182 The conversion combinator @{ML_ind else_conv in Conv} tries out the |
2182 The conversion combinator @{ML_ind else_conv in Conv} tries out the |
2183 first one, and if it does not apply, tries the second. For example |
2183 first one, and if it does not apply, tries the second. For example |
2184 |
2184 |
2185 @{ML_matchresult_fake [display,gray] |
2185 @{ML_matchresult_fake [display,gray] |
2186 "let |
2186 \<open>let |
2187 val conv = Conv.rewr_conv @{thm true_conj1} else_conv Conv.all_conv |
2187 val conv = Conv.rewr_conv @{thm true_conj1} else_conv Conv.all_conv |
2188 val ctrm1 = @{cterm \"True \<and> Q\"} |
2188 val ctrm1 = @{cterm "True \<and> Q"} |
2189 val ctrm2 = @{cterm \"P \<or> (True \<and> Q)\"} |
2189 val ctrm2 = @{cterm "P \<or> (True \<and> Q)"} |
2190 in |
2190 in |
2191 (conv ctrm1, conv ctrm2) |
2191 (conv ctrm1, conv ctrm2) |
2192 end" |
2192 end\<close> |
2193 "(True \<and> Q \<equiv> Q, P \<or> True \<and> Q \<equiv> P \<or> True \<and> Q)"} |
2193 \<open>(True \<and> Q \<equiv> Q, P \<or> True \<and> Q \<equiv> P \<or> True \<and> Q)\<close>} |
2194 |
2194 |
2195 Here the conversion @{thm [source] true_conj1} only applies |
2195 Here the conversion @{thm [source] true_conj1} only applies |
2196 in the first case, but fails in the second. The whole conversion |
2196 in the first case, but fails in the second. The whole conversion |
2197 does not fail, however, because the combinator @{ML else_conv in Conv} will then |
2197 does not fail, however, because the combinator @{ML else_conv in Conv} will then |
2198 try out @{ML all_conv in Conv}, which always succeeds. The same |
2198 try out @{ML all_conv in Conv}, which always succeeds. The same |
2199 behaviour can also be achieved with conversion combinator @{ML_ind try_conv in Conv}. |
2199 behaviour can also be achieved with conversion combinator @{ML_ind try_conv in Conv}. |
2200 For example |
2200 For example |
2201 |
2201 |
2202 @{ML_matchresult_fake [display,gray] |
2202 @{ML_matchresult_fake [display,gray] |
2203 "let |
2203 \<open>let |
2204 val conv = Conv.try_conv (Conv.rewr_conv @{thm true_conj1}) |
2204 val conv = Conv.try_conv (Conv.rewr_conv @{thm true_conj1}) |
2205 val ctrm = @{cterm \"True \<or> P\"} |
2205 val ctrm = @{cterm "True \<or> P"} |
2206 in |
2206 in |
2207 conv ctrm |
2207 conv ctrm |
2208 end" |
2208 end\<close> |
2209 "True \<or> P \<equiv> True \<or> P"} |
2209 \<open>True \<or> P \<equiv> True \<or> P\<close>} |
2210 |
2210 |
2211 Rewriting with more than one theorem can be done using the function |
2211 Rewriting with more than one theorem can be done using the function |
2212 @{ML_ind rewrs_conv in Conv} from the structure @{ML_structure Conv}. |
2212 @{ML_ind rewrs_conv in Conv} from the structure @{ML_structure Conv}. |
2213 |
2213 |
2214 |
2214 |
2219 and @{ML_ind arg_conv in Conv} will apply |
2219 and @{ML_ind arg_conv in Conv} will apply |
2220 a conversion to the first, respectively second, argument of an application. |
2220 a conversion to the first, respectively second, argument of an application. |
2221 For example |
2221 For example |
2222 |
2222 |
2223 @{ML_matchresult_fake [display,gray] |
2223 @{ML_matchresult_fake [display,gray] |
2224 "let |
2224 \<open>let |
2225 val conv = Conv.arg_conv (Conv.rewr_conv @{thm true_conj1}) |
2225 val conv = Conv.arg_conv (Conv.rewr_conv @{thm true_conj1}) |
2226 val ctrm = @{cterm \"P \<or> (True \<and> Q)\"} |
2226 val ctrm = @{cterm "P \<or> (True \<and> Q)"} |
2227 in |
2227 in |
2228 conv ctrm |
2228 conv ctrm |
2229 end" |
2229 end\<close> |
2230 "P \<or> (True \<and> Q) \<equiv> P \<or> Q"} |
2230 \<open>P \<or> (True \<and> Q) \<equiv> P \<or> Q\<close>} |
2231 |
2231 |
2232 The reason for this behaviour is that \<open>(op \<or>)\<close> expects two |
2232 The reason for this behaviour is that \<open>(op \<or>)\<close> expects two |
2233 arguments. Therefore the term must be of the form \<open>(Const \<dots> $ t1) $ t2\<close>. The |
2233 arguments. Therefore the term must be of the form \<open>(Const \<dots> $ t1) $ t2\<close>. The |
2234 conversion is then applied to \<open>t2\<close>, which in the example above |
2234 conversion is then applied to \<open>t2\<close>, which in the example above |
2235 stands for @{term "True \<and> Q"}. The function @{ML fun_conv in Conv} would apply |
2235 stands for @{term "True \<and> Q"}. The function @{ML fun_conv in Conv} would apply |
2237 |
2237 |
2238 The function @{ML_ind abs_conv in Conv} applies a conversion under an |
2238 The function @{ML_ind abs_conv in Conv} applies a conversion under an |
2239 abstraction. For example: |
2239 abstraction. For example: |
2240 |
2240 |
2241 @{ML_matchresult_fake [display,gray] |
2241 @{ML_matchresult_fake [display,gray] |
2242 "let |
2242 \<open>let |
2243 val conv = Conv.rewr_conv @{thm true_conj1} |
2243 val conv = Conv.rewr_conv @{thm true_conj1} |
2244 val ctrm = @{cterm \"\<lambda>P. True \<and> (P \<and> Foo)\"} |
2244 val ctrm = @{cterm "\<lambda>P. True \<and> (P \<and> Foo)"} |
2245 in |
2245 in |
2246 Conv.abs_conv (K conv) @{context} ctrm |
2246 Conv.abs_conv (K conv) @{context} ctrm |
2247 end" |
2247 end\<close> |
2248 "\<lambda>P. True \<and> (P \<and> Foo) \<equiv> \<lambda>P. P \<and> Foo"} |
2248 \<open>\<lambda>P. True \<and> (P \<and> Foo) \<equiv> \<lambda>P. P \<and> Foo\<close>} |
2249 |
2249 |
2250 Note that this conversion needs a context as an argument. We also give the |
2250 Note that this conversion needs a context as an argument. We also give the |
2251 conversion as \<open>(K conv)\<close>, which is a function that ignores its |
2251 conversion as \<open>(K conv)\<close>, which is a function that ignores its |
2252 argument (the argument being a sufficiently freshened version of the |
2252 argument (the argument being a sufficiently freshened version of the |
2253 variable that is abstracted and a context). The conversion that goes under |
2253 variable that is abstracted and a context). The conversion that goes under |
2278 we need to transform the @{ML_type cterm} into a @{ML_type term} in order |
2278 we need to transform the @{ML_type cterm} into a @{ML_type term} in order |
2279 to be able to pattern-match the term. To see this |
2279 to be able to pattern-match the term. To see this |
2280 conversion in action, consider the following example: |
2280 conversion in action, consider the following example: |
2281 |
2281 |
2282 @{ML_matchresult_fake [display,gray] |
2282 @{ML_matchresult_fake [display,gray] |
2283 "let |
2283 \<open>let |
2284 val conv = true_conj1_conv @{context} |
2284 val conv = true_conj1_conv @{context} |
2285 val ctrm = @{cterm \"distinct [1::nat, x] \<longrightarrow> True \<and> 1 \<noteq> x\"} |
2285 val ctrm = @{cterm "distinct [1::nat, x] \<longrightarrow> True \<and> 1 \<noteq> x"} |
2286 in |
2286 in |
2287 conv ctrm |
2287 conv ctrm |
2288 end" |
2288 end\<close> |
2289 "distinct [1, x] \<longrightarrow> True \<and> 1 \<noteq> x \<equiv> distinct [1, x] \<longrightarrow> 1 \<noteq> x"} |
2289 \<open>distinct [1, x] \<longrightarrow> True \<and> 1 \<noteq> x \<equiv> distinct [1, x] \<longrightarrow> 1 \<noteq> x\<close>} |
2290 \<close> |
2290 \<close> |
2291 |
2291 |
2292 text \<open> |
2292 text \<open> |
2293 Conversions that traverse terms, like @{ML true_conj1_conv} above, can be |
2293 Conversions that traverse terms, like @{ML true_conj1_conv} above, can be |
2294 implemented more succinctly with the combinators @{ML_ind bottom_conv in |
2294 implemented more succinctly with the combinators @{ML_ind bottom_conv in |
2321 pause for a moment to be convinced that rewriting top-down and bottom-up |
2321 pause for a moment to be convinced that rewriting top-down and bottom-up |
2322 according to the two meta-equations produces two results. Below these |
2322 according to the two meta-equations produces two results. Below these |
2323 two results are calculated. |
2323 two results are calculated. |
2324 |
2324 |
2325 @{ML_matchresult_fake [display, gray] |
2325 @{ML_matchresult_fake [display, gray] |
2326 "let |
2326 \<open>let |
2327 val ctxt = @{context} |
2327 val ctxt = @{context} |
2328 val conv = Conv.try_conv (Conv.rewrs_conv @{thms conj_assoc}) |
2328 val conv = Conv.try_conv (Conv.rewrs_conv @{thms conj_assoc}) |
2329 val conv_top = Conv.top_conv (K conv) ctxt |
2329 val conv_top = Conv.top_conv (K conv) ctxt |
2330 val conv_bot = Conv.bottom_conv (K conv) ctxt |
2330 val conv_bot = Conv.bottom_conv (K conv) ctxt |
2331 val ctrm = @{cterm \"(a \<and> (b \<and> c)) \<and> d\"} |
2331 val ctrm = @{cterm "(a \<and> (b \<and> c)) \<and> d"} |
2332 in |
2332 in |
2333 (conv_top ctrm, conv_bot ctrm) |
2333 (conv_top ctrm, conv_bot ctrm) |
2334 end" |
2334 end\<close> |
2335 "(\"(a \<and> (b \<and> c)) \<and> d \<equiv> a \<and> (b \<and> (c \<and> d))\", |
2335 \<open>("(a \<and> (b \<and> c)) \<and> d \<equiv> a \<and> (b \<and> (c \<and> d))", |
2336 \"(a \<and> (b \<and> c)) \<and> d \<equiv> (a \<and> b) \<and> (c \<and> d)\")"} |
2336 "(a \<and> (b \<and> c)) \<and> d \<equiv> (a \<and> b) \<and> (c \<and> d)")\<close>} |
2337 |
2337 |
2338 To see how much control you have over rewriting with conversions, let us |
2338 To see how much control you have over rewriting with conversions, let us |
2339 make the task a bit more complicated by rewriting according to the rule |
2339 make the task a bit more complicated by rewriting according to the rule |
2340 \<open>true_conj1\<close>, but only in the first arguments of @{term If}s. Then |
2340 \<open>true_conj1\<close>, but only in the first arguments of @{term If}s. Then |
2341 the conversion should be as follows. |
2341 the conversion should be as follows. |
2357 root and applies it to all the redexes on the way, but stops in each branch as |
2357 root and applies it to all the redexes on the way, but stops in each branch as |
2358 soon as it found one redex. Here is an example for this conversion: |
2358 soon as it found one redex. Here is an example for this conversion: |
2359 |
2359 |
2360 |
2360 |
2361 @{ML_matchresult_fake [display,gray] |
2361 @{ML_matchresult_fake [display,gray] |
2362 "let |
2362 \<open>let |
2363 val ctrm = @{cterm \"if P (True \<and> 1 \<noteq> (2::nat)) |
2363 val ctrm = @{cterm "if P (True \<and> 1 \<noteq> (2::nat)) |
2364 then True \<and> True else True \<and> False\"} |
2364 then True \<and> True else True \<and> False"} |
2365 in |
2365 in |
2366 if_true1_conv @{context} ctrm |
2366 if_true1_conv @{context} ctrm |
2367 end" |
2367 end\<close> |
2368 "if P (True \<and> 1 \<noteq> 2) then True \<and> True else True \<and> False |
2368 \<open>if P (True \<and> 1 \<noteq> 2) then True \<and> True else True \<and> False |
2369 \<equiv> if P (1 \<noteq> 2) then True \<and> True else True \<and> False"} |
2369 \<equiv> if P (1 \<noteq> 2) then True \<and> True else True \<and> False\<close>} |
2370 \<close> |
2370 \<close> |
2371 |
2371 |
2372 text \<open> |
2372 text \<open> |
2373 So far we only applied conversions to @{ML_type cterm}s. Conversions can, however, |
2373 So far we only applied conversions to @{ML_type cterm}s. Conversions can, however, |
2374 also work on theorems using the function @{ML_ind fconv_rule in Conv}. As an example, |
2374 also work on theorems using the function @{ML_ind fconv_rule in Conv}. As an example, |