ProgTutorial/Tactical.thy
changeset 569 f875a25aa72d
parent 567 f7c97e64cc2a
child 572 438703674711
equal deleted inserted replaced
568:be23597e81db 569:f875a25aa72d
    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}
   979 
   979 
   980 text \<open>
   980 text \<open>
   981   There is even another way of implementing this tactic: in automatic proof
   981   There is even another way of implementing this tactic: in automatic proof
   982   procedures (in contrast to tactics that might be called by the user) there
   982   procedures (in contrast to tactics that might be called by the user) there
   983   are often long lists of tactics that are applied to the first
   983   are often long lists of tactics that are applied to the first
   984   subgoal. Instead of writing the code above and then calling @{ML "foo_tac'' @{context} 1"}, 
   984   subgoal. Instead of writing the code above and then calling @{ML \<open>foo_tac'' @{context} 1\<close>}, 
   985   you can also just write
   985   you can also just write
   986 \<close>
   986 \<close>
   987 
   987 
   988 ML %grayML\<open>fun foo_tac1 ctxt = 
   988 ML %grayML\<open>fun foo_tac1 ctxt = 
   989   EVERY1 [eresolve_tac ctxt [@{thm disjE}], resolve_tac ctxt [@{thm disjI2}], 
   989   EVERY1 [eresolve_tac ctxt [@{thm disjE}], resolve_tac ctxt [@{thm disjI2}], 
  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>
  1473 
  1473 
  1474 text \<open>
  1474 text \<open>
  1475   Printing then out the components of the simpset gives:
  1475   Printing then out the components of the simpset gives:
  1476 
  1476 
  1477   @{ML_matchresult_fake [display,gray]
  1477   @{ML_matchresult_fake [display,gray]
  1478   "print_ss @{context} (Raw_Simplifier.simpset_of ss1)"
  1478   \<open>print_ss @{context} (Raw_Simplifier.simpset_of ss1)\<close>
  1479 "Simplification rules:
  1479 \<open>Simplification rules:
  1480   ??.unknown: A - B \<inter> C \<equiv> A - B \<union> (A - C)
  1480   ??.unknown: A - B \<inter> C \<equiv> A - B \<union> (A - C)
  1481 Congruences rules:
  1481 Congruences rules:
  1482 Simproc patterns:"}
  1482 Simproc patterns:\<close>}
  1483 
  1483 
  1484   \footnote{\bf FIXME: Why does it print out ??.unknown}
  1484   \footnote{\bf FIXME: Why does it print out ??.unknown}
  1485 
  1485 
  1486   Adding also the congruence rule @{thm [source] strong_INF_cong} 
  1486   Adding also the congruence rule @{thm [source] strong_INF_cong} 
  1487 \<close>
  1487 \<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}
  1753   (FIXME: What are the second components of the congruence rules---something to
  1753   (FIXME: What are the second components of the congruence rules---something to
  1754   do with weak congruence constants?)
  1754   do with weak congruence constants?)
  1755 
  1755 
  1756   (FIXME: what are @{ML mksimps_pairs}; used in Nominal.thy)
  1756   (FIXME: what are @{ML mksimps_pairs}; used in Nominal.thy)
  1757 
  1757 
  1758   (FIXME: explain @{ML simplify} and @{ML "Simplifier.rewrite_rule"} etc.)
  1758   (FIXME: explain @{ML simplify} and @{ML \<open>Simplifier.rewrite_rule\<close>} etc.)
  1759 
  1759 
  1760 \<close>
  1760 \<close>
  1761 
  1761 
  1762 section \<open>Simprocs\<close>
  1762 section \<open>Simprocs\<close>
  1763 
  1763 
  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, 
  2381 text \<open>
  2381 text \<open>
  2382   Using the conversion you can transform this theorem into a 
  2382   Using the conversion you can transform this theorem into a 
  2383   new theorem as follows
  2383   new theorem as follows
  2384 
  2384 
  2385   @{ML_matchresult_fake [display,gray]
  2385   @{ML_matchresult_fake [display,gray]
  2386 "let
  2386 \<open>let
  2387   val conv = Conv.fconv_rule (true_conj1_conv @{context}) 
  2387   val conv = Conv.fconv_rule (true_conj1_conv @{context}) 
  2388   val thm = @{thm foo_test}
  2388   val thm = @{thm foo_test}
  2389 in
  2389 in
  2390   conv thm
  2390   conv thm
  2391 end" 
  2391 end\<close> 
  2392   "?P \<or> \<not> ?P"}
  2392   \<open>?P \<or> \<not> ?P\<close>}
  2393 
  2393 
  2394   Finally, Isabelle provides function @{ML_ind CONVERSION in Tactical} 
  2394   Finally, Isabelle provides function @{ML_ind CONVERSION in Tactical} 
  2395   for turning conversions into tactics. This needs some predefined conversion 
  2395   for turning conversions into tactics. This needs some predefined conversion 
  2396   combinators that traverse a goal
  2396   combinators that traverse a goal
  2397   state and can selectively apply the conversion. The combinators for 
  2397   state and can selectively apply the conversion. The combinators for 
  2418     (Conv.params_conv ~1 (fn ctxt =>
  2418     (Conv.params_conv ~1 (fn ctxt =>
  2419        (Conv.prems_conv ~1 (if_true1_conv ctxt) then_conv
  2419        (Conv.prems_conv ~1 (if_true1_conv ctxt) then_conv
  2420           Conv.concl_conv ~1 (true_conj1_conv ctxt))) ctxt)\<close>
  2420           Conv.concl_conv ~1 (true_conj1_conv ctxt))) ctxt)\<close>
  2421 
  2421 
  2422 text \<open>
  2422 text \<open>
  2423   We call the conversions with the argument @{ML "~1"}. By this we 
  2423   We call the conversions with the argument @{ML \<open>~1\<close>}. By this we 
  2424   analyse all parameters, all premises and the conclusion of a goal
  2424   analyse all parameters, all premises and the conclusion of a goal
  2425   state. If we call @{ML concl_conv in Conv} with 
  2425   state. If we call @{ML concl_conv in Conv} with 
  2426   a non-negative number, say \<open>n\<close>, then this conversions will 
  2426   a non-negative number, say \<open>n\<close>, then this conversions will 
  2427   skip the first \<open>n\<close> premises and applies the conversion to the 
  2427   skip the first \<open>n\<close> premises and applies the conversion to the 
  2428   ``rest'' (similar for parameters and conclusions). To test the 
  2428   ``rest'' (similar for parameters and conclusions). To test the 
  2464   theorem @{thm [source] id1_def}
  2464   theorem @{thm [source] id1_def}
  2465   into @{thm [source] id2_def} by abstracting all variables on the 
  2465   into @{thm [source] id2_def} by abstracting all variables on the 
  2466   left-hand side in the right-hand side.
  2466   left-hand side in the right-hand side.
  2467 
  2467 
  2468   @{ML_matchresult_fake [display,gray]
  2468   @{ML_matchresult_fake [display,gray]
  2469   "Drule.abs_def @{thm id1_def}"
  2469   \<open>Drule.abs_def @{thm id1_def}\<close>
  2470   "id1 \<equiv> \<lambda>x. x"}
  2470   \<open>id1 \<equiv> \<lambda>x. x\<close>}
  2471 
  2471 
  2472   Unfortunately, Isabelle has no built-in function that transforms the
  2472   Unfortunately, Isabelle has no built-in function that transforms the
  2473   theorems in the other direction. We can implement one using
  2473   theorems in the other direction. We can implement one using
  2474   conversions. The feature of conversions we are using is that if we apply a
  2474   conversions. The feature of conversions we are using is that if we apply a
  2475   @{ML_type cterm} to a conversion we obtain a meta-equality theorem (recall
  2475   @{ML_type cterm} to a conversion we obtain a meta-equality theorem (recall
  2512   theorem we want to construct. As mentioned above, in Line 15 we only have to
  2512   theorem we want to construct. As mentioned above, in Line 15 we only have to
  2513   export the context \<open>ctxt'\<close> back to \<open>ctxt\<close> in order to 
  2513   export the context \<open>ctxt'\<close> back to \<open>ctxt\<close> in order to 
  2514   produce meta-variables for the theorem.  An example is as follows.
  2514   produce meta-variables for the theorem.  An example is as follows.
  2515 
  2515 
  2516   @{ML_matchresult_fake [display, gray]
  2516   @{ML_matchresult_fake [display, gray]
  2517   "unabs_def @{context} @{thm id2_def}"
  2517   \<open>unabs_def @{context} @{thm id2_def}\<close>
  2518   "id2 ?x1 \<equiv> ?x1"}
  2518   \<open>id2 ?x1 \<equiv> ?x1\<close>}
  2519 \<close>
  2519 \<close>
  2520 
  2520 
  2521 text \<open>
  2521 text \<open>
  2522   To sum up this section, conversions are more general than the simplifier
  2522   To sum up this section, conversions are more general than the simplifier
  2523   or simprocs, but you have to do more work yourself. Also conversions are
  2523   or simprocs, but you have to do more work yourself. Also conversions are