CookBook/Tactical.thy
changeset 160 cc9359bfacf4
parent 158 d7944bdf7b3f
child 161 83f36a1c62f2
equal deleted inserted replaced
159:64fa844064fa 160:cc9359bfacf4
  1092   and @{ML_file "Pure/simplifier.ML"}. The simplifier for HOL is set up in 
  1092   and @{ML_file "Pure/simplifier.ML"}. The simplifier for HOL is set up in 
  1093   @{ML_file "HOL/Tools/simpdata.ML"}. Generic splitters are implemented in 
  1093   @{ML_file "HOL/Tools/simpdata.ML"}. Generic splitters are implemented in 
  1094   @{ML_file  "Provers/splitter.ML"}.
  1094   @{ML_file  "Provers/splitter.ML"}.
  1095   \end{readmore}
  1095   \end{readmore}
  1096 
  1096 
       
  1097   \begin{readmore}
       
  1098   FIXME: Find the right place Discrimination nets are implemented
       
  1099   in @{ML_file "Pure/net.ML"}.
       
  1100   \end{readmore}
       
  1101 
  1097   The most common combinators to modify simpsets are
  1102   The most common combinators to modify simpsets are
  1098 
  1103 
  1099   \begin{isabelle}
  1104   \begin{isabelle}
  1100   \begin{tabular}{ll}
  1105   \begin{tabular}{ll}
  1101   @{ML addsimps}   & @{ML delsimps}\\
  1106   @{ML addsimps}   & @{ML delsimps}\\
  1709   @{ML_response_fake [display,gray]
  1714   @{ML_response_fake [display,gray]
  1710   "Conv.no_conv @{cterm True}" 
  1715   "Conv.no_conv @{cterm True}" 
  1711   "*** Exception- CTERM (\"no conversion\", []) raised"}
  1716   "*** Exception- CTERM (\"no conversion\", []) raised"}
  1712 
  1717 
  1713   A more interesting conversion is the function @{ML "Thm.beta_conversion"}: it 
  1718   A more interesting conversion is the function @{ML "Thm.beta_conversion"}: it 
  1714   produces an equation between a term and its beta-normal form. For example
  1719   produces a meta-equation between a term and its beta-normal form. For example
  1715 
  1720 
  1716   @{ML_response_fake [display,gray]
  1721   @{ML_response_fake [display,gray]
  1717   "let
  1722   "let
  1718   val add = @{cterm \"\<lambda>x y. x + (y::nat)\"}
  1723   val add = @{cterm \"\<lambda>x y. x + (y::nat)\"}
  1719   val two = @{cterm \"2::nat\"}
  1724   val two = @{cterm \"2::nat\"}
  1722   Thm.beta_conversion true (Thm.capply (Thm.capply add two) ten)
  1727   Thm.beta_conversion true (Thm.capply (Thm.capply add two) ten)
  1723 end"
  1728 end"
  1724   "((\<lambda>x y. x + y) 2) 10 \<equiv> 2 + 10"}
  1729   "((\<lambda>x y. x + y) 2) 10 \<equiv> 2 + 10"}
  1725 
  1730 
  1726   Note that the actual response in this example is @{term "2 + 10 \<equiv> 2 + (10::nat)"}, 
  1731   Note that the actual response in this example is @{term "2 + 10 \<equiv> 2 + (10::nat)"}, 
  1727   since the pretty printer for @{ML_type cterm}s already beta-normalises terms.
  1732   since the pretty-printer for @{ML_type cterm}s already beta-normalises terms.
  1728   But by the way how we constructed the term (using the function 
  1733   But by the way how we constructed the term (using the function 
  1729   @{ML Thm.capply}, which is the application @{ML $} for @{ML_type cterm}s),
  1734   @{ML Thm.capply}, which is the application @{ML $} for @{ML_type cterm}s),
  1730   we can be sure the left-hand side must contain beta-redexes. Indeed
  1735   we can be sure the left-hand side must contain beta-redexes. Indeed
  1731   if we obtain the ``raw'' representation of the produced theorem, we
  1736   if we obtain the ``raw'' representation of the produced theorem, we
  1732   can see the difference:
  1737   can see the difference:
  1734   @{ML_response [display,gray]
  1739   @{ML_response [display,gray]
  1735 "let
  1740 "let
  1736   val add = @{cterm \"\<lambda>x y. x + (y::nat)\"}
  1741   val add = @{cterm \"\<lambda>x y. x + (y::nat)\"}
  1737   val two = @{cterm \"2::nat\"}
  1742   val two = @{cterm \"2::nat\"}
  1738   val ten = @{cterm \"10::nat\"}
  1743   val ten = @{cterm \"10::nat\"}
  1739 in
  1744   val thm = Thm.beta_conversion true (Thm.capply (Thm.capply add two) ten)
  1740   #prop (rep_thm 
  1745 in
  1741           (Thm.beta_conversion true (Thm.capply (Thm.capply add two) ten)))
  1746   #prop (rep_thm thm)
  1742 end"
  1747 end"
  1743 "Const (\"==\",\<dots>) $ 
  1748 "Const (\"==\",\<dots>) $ 
  1744   (Abs (\"x\",\<dots>,Abs (\"y\",\<dots>,\<dots>)) $\<dots>$\<dots>) $ 
  1749   (Abs (\"x\",\<dots>,Abs (\"y\",\<dots>,\<dots>)) $\<dots>$\<dots>) $ 
  1745     (Const (\"HOL.plus_class.plus\",\<dots>) $ \<dots> $ \<dots>)"} 
  1750     (Const (\"HOL.plus_class.plus\",\<dots>) $ \<dots> $ \<dots>)"} 
  1746 
  1751 
  1761   Again, we actually see as output only the fully normalised term 
  1766   Again, we actually see as output only the fully normalised term 
  1762   @{text "\<lambda>y. 2 + y"}.
  1767   @{text "\<lambda>y. 2 + y"}.
  1763 
  1768 
  1764   The main point of conversions is that they can be used for rewriting
  1769   The main point of conversions is that they can be used for rewriting
  1765   @{ML_type cterm}s. To do this you can use the function @{ML
  1770   @{ML_type cterm}s. To do this you can use the function @{ML
  1766   "Conv.rewr_conv"} which expects a meta-equation as an argument. Suppose we
  1771   "Conv.rewr_conv"}, which expects a meta-equation as an argument. Suppose we
  1767   want to rewrite a @{ML_type cterm} according to the (meta)equation:
  1772   want to rewrite a @{ML_type cterm} according to the meta-equation:
  1768 *}
  1773 *}
  1769 
  1774 
  1770 lemma true_conj1: "True \<and> P \<equiv> P" by simp
  1775 lemma true_conj1: "True \<and> P \<equiv> P" by simp
  1771 
  1776 
  1772 text {* 
  1777 text {* 
  1773   You can see how this function works with the example 
  1778   You can see how this function works in the example rewriting 
  1774   @{term "True \<and> (Foo \<longrightarrow> Bar)"}:
  1779   the @{ML_type cterm} @{term "True \<and> (Foo \<longrightarrow> Bar)"} to @{term "Foo \<longrightarrow> Bar"}.
  1775 
  1780 
  1776   @{ML_response_fake [display,gray]
  1781   @{ML_response_fake [display,gray]
  1777 "let 
  1782 "let 
  1778   val ctrm = @{cterm \"True \<and> (Foo \<longrightarrow> Bar)\"}
  1783   val ctrm = @{cterm \"True \<and> (Foo \<longrightarrow> Bar)\"}
  1779 in
  1784 in
  1780   Conv.rewr_conv @{thm true_conj1} ctrm
  1785   Conv.rewr_conv @{thm true_conj1} ctrm
  1781 end"
  1786 end"
  1782   "True \<and> (Foo \<longrightarrow> Bar) \<equiv> Foo \<longrightarrow> Bar"}
  1787   "True \<and> (Foo \<longrightarrow> Bar) \<equiv> Foo \<longrightarrow> Bar"}
  1783 
  1788 
  1784   Note, however, that the function @{ML Conv.rewr_conv} only rewrites the 
  1789   Note, however, that the function @{ML Conv.rewr_conv} only rewrites the 
  1785   outer-most level of the @{ML_type cterm}. If the given @{ML_type cterm} does not match the 
  1790   outer-most level of the @{ML_type cterm}. If the given @{ML_type cterm} does not match 
       
  1791   exactly the 
  1786   left-hand side of the theorem, then  @{ML Conv.rewr_conv} raises 
  1792   left-hand side of the theorem, then  @{ML Conv.rewr_conv} raises 
  1787   the exception @{ML CTERM}.
  1793   the exception @{ML CTERM}.
  1788 
  1794 
  1789   This very primitive way of rewriting can be made more powerful by
  1795   This very primitive way of rewriting can be made more powerful by
  1790   combining several conversions into one. For this you can use conversion
  1796   combining several conversions into one. For this you can use conversion
  1839   Conv.arg_conv conv ctrm
  1845   Conv.arg_conv conv ctrm
  1840 end"
  1846 end"
  1841 "P \<or> (True \<and> Q) \<equiv> P \<or> Q"}
  1847 "P \<or> (True \<and> Q) \<equiv> P \<or> Q"}
  1842 
  1848 
  1843   The reason for this behaviour is that @{text "(op \<or>)"} expects two
  1849   The reason for this behaviour is that @{text "(op \<or>)"} expects two
  1844   arguments.  So the term must be of the form @{text "(Const \<dots> $ t1) $ t2"}. The
  1850   arguments.  Therefore the term must be of the form @{text "(Const \<dots> $ t1) $ t2"}. The
  1845   conversion is then applied to @{text "t2"} which in the example above
  1851   conversion is then applied to @{text "t2"} which in the example above
  1846   stands for @{term "True \<and> Q"}. The function @{ML Conv.fun_conv} applies
  1852   stands for @{term "True \<and> Q"}. The function @{ML Conv.fun_conv} applies
  1847   the conversion to the first argument of an application.
  1853   the conversion to the first argument of an application.
  1848 
  1854 
  1849   The function @{ML Conv.abs_conv} applies a conversion under an abstractions.
  1855   The function @{ML Conv.abs_conv} applies a conversion under an abstractions.
  1856 in
  1862 in
  1857   Conv.abs_conv conv @{context} ctrm
  1863   Conv.abs_conv conv @{context} ctrm
  1858 end"
  1864 end"
  1859   "\<lambda>P. True \<and> P \<and> Foo \<equiv> \<lambda>P. P \<and> Foo"}
  1865   "\<lambda>P. True \<and> P \<and> Foo \<equiv> \<lambda>P. P \<and> Foo"}
  1860   
  1866   
  1861   The conversion that goes under an application is
  1867   Note that this conversion needs a context as an argument. The conversion that 
  1862   @{ML Conv.combination_conv}. It expects two conversions as arguments, 
  1868   goes under an application is @{ML Conv.combination_conv}. It expects two conversions 
  1863   each of which is applied to the corresponding ``branch'' of the application. 
  1869   as arguments, each of which is applied to the corresponding ``branch'' of the
  1864 
  1870   application. 
  1865   We can now apply all these functions in a
  1871 
  1866   conversion that recursively descends a term and applies a conversion in all
  1872   We can now apply all these functions in a conversion that recursively
  1867   possible positions.
  1873   descends a term and applies a ``@{thm [source] true_conj1}''-conversion 
       
  1874   in all possible positions.
  1868 *}
  1875 *}
  1869 
  1876 
  1870 ML %linenosgray{*fun all_true1_conv ctxt ctrm =
  1877 ML %linenosgray{*fun all_true1_conv ctxt ctrm =
  1871   case (Thm.term_of ctrm) of
  1878   case (Thm.term_of ctrm) of
  1872     @{term "op \<and>"} $ @{term True} $ _ => 
  1879     @{term "op \<and>"} $ @{term True} $ _ => 
  1873       (Conv.arg_conv (all_true1_conv ctxt) then_conv
  1880       (Conv.arg_conv (all_true1_conv ctxt) then_conv
  1874          Conv.rewr_conv @{thm true_conj1}) ctrm
  1881          Conv.rewr_conv @{thm true_conj1}) ctrm
  1875   | _ $ _ => Conv.combination_conv 
  1882   | _ $ _ => Conv.combination_conv 
  1876                  (all_true1_conv ctxt) (all_true1_conv ctxt) ctrm
  1883                (all_true1_conv ctxt) (all_true1_conv ctxt) ctrm
  1877   | Abs _ => Conv.abs_conv (fn (_, ctxt) => all_true1_conv ctxt) ctxt ctrm
  1884   | Abs _ => Conv.abs_conv (fn (_, ctxt) => all_true1_conv ctxt) ctxt ctrm
  1878   | _ => Conv.all_conv ctrm*}
  1885   | _ => Conv.all_conv ctrm*}
  1879 
  1886 
  1880 text {*
  1887 text {*
  1881   This functions descends under applications (Line 6 and 7) and abstractions 
  1888   This function ``fires'' if the terms is of the form @{text "True \<and> \<dots>"}; 
  1882   (Line 8); and ``fires'' if the outer-most constant is an @{text "True \<and> \<dots>"}
  1889   it descends under applications (Line 6 and 7) and abstractions 
  1883   (Lines 3-5); otherwise it leaves the term unchanged (Line 9). In Line 2
  1890   (Line 8); otherwise it leaves the term unchanged (Line 9). In Line 2
  1884   we need to transform the @{ML_type cterm} into a @{ML_type term} in order
  1891   we need to transform the @{ML_type cterm} into a @{ML_type term} in order
  1885   to be able to pattern-match the term. To see this 
  1892   to be able to pattern-match the term. To see this 
  1886   conversion in action, consider the following example
  1893   conversion in action, consider the following example:
  1887 
  1894 
  1888 @{ML_response_fake [display,gray]
  1895 @{ML_response_fake [display,gray]
  1889 "let
  1896 "let
  1890   val ctxt = @{context}
  1897   val ctxt = @{context}
  1891   val ctrm = @{cterm \"distinct [1, x] \<longrightarrow> True \<and> 1 \<noteq> x\"}
  1898   val ctrm = @{cterm \"distinct [1, x] \<longrightarrow> True \<and> 1 \<noteq> x\"}
  1892 in
  1899 in
  1893   all_true1_conv ctxt ctrm
  1900   all_true1_conv ctxt ctrm
  1894 end"
  1901 end"
  1895   "distinct [1, x] \<longrightarrow> True \<and> 1 \<noteq> x \<equiv> distinct [1, x] \<longrightarrow> 1 \<noteq> x"}
  1902   "distinct [1, x] \<longrightarrow> True \<and> 1 \<noteq> x \<equiv> distinct [1, x] \<longrightarrow> 1 \<noteq> x"}
  1896 
       
  1897   where the conversion is applied ``deep'' inside the term.
       
  1898 
  1903 
  1899   To see how much control you have about rewriting by using conversions, let us 
  1904   To see how much control you have about rewriting by using conversions, let us 
  1900   make the task a bit more complicated by rewriting according to the rule
  1905   make the task a bit more complicated by rewriting according to the rule
  1901   @{text true_conj1}, but only in the first arguments of @{term If}s. Then 
  1906   @{text true_conj1}, but only in the first arguments of @{term If}s. Then 
  1902   the conversion should be as follows.
  1907   the conversion should be as follows.
  1905 ML{*fun if_true1_conv ctxt ctrm =
  1910 ML{*fun if_true1_conv ctxt ctrm =
  1906   case Thm.term_of ctrm of
  1911   case Thm.term_of ctrm of
  1907     Const (@{const_name If}, _) $ _ =>
  1912     Const (@{const_name If}, _) $ _ =>
  1908       Conv.arg_conv (all_true1_conv ctxt) ctrm
  1913       Conv.arg_conv (all_true1_conv ctxt) ctrm
  1909   | _ $ _ => Conv.combination_conv 
  1914   | _ $ _ => Conv.combination_conv 
  1910                         (if_true1_conv ctxt) (if_true1_conv ctxt) ctrm
  1915                 (if_true1_conv ctxt) (if_true1_conv ctxt) ctrm
  1911   | Abs _ => Conv.abs_conv (fn (_, ctxt) => if_true1_conv ctxt) ctxt ctrm
  1916   | Abs _ => Conv.abs_conv (fn (_, ctxt) => if_true1_conv ctxt) ctxt ctrm
  1912   | _ => Conv.all_conv ctrm *}
  1917   | _ => Conv.all_conv ctrm *}
  1913 
  1918 
  1914 text {*
  1919 text {*
  1915   Here is an example for this conversion:
  1920   Here is an example for this conversion:
  1916 
  1921 
  1917   @{ML_response_fake [display,gray]
  1922   @{ML_response_fake [display,gray]
  1918 "let
  1923 "let
  1919   val ctxt = @{context}
  1924   val ctxt = @{context}
  1920   val ctrm = 
  1925   val ctrm = 
  1921      @{cterm \"if P (True \<and> 1 \<noteq> 2) then True \<and> True else True \<and> False\"}
  1926        @{cterm \"if P (True \<and> 1 \<noteq> 2) then True \<and> True else True \<and> False\"}
  1922 in
  1927 in
  1923   if_true1_conv ctxt ctrm
  1928   if_true1_conv ctxt ctrm
  1924 end"
  1929 end"
  1925 "if P (True \<and> 1 \<noteq> 2) then True \<and> True else True \<and> False 
  1930 "if P (True \<and> 1 \<noteq> 2) then True \<and> True else True \<and> False 
  1926 \<equiv> if P (1 \<noteq> 2) then True \<and> True else True \<and> False"}
  1931 \<equiv> if P (1 \<noteq> 2) then True \<and> True else True \<and> False"}
  1942   "Conv.fconv_rule (all_true1_conv @{context}) @{thm foo_test}" 
  1947   "Conv.fconv_rule (all_true1_conv @{context}) @{thm foo_test}" 
  1943   "?P \<or> \<not> ?P"}
  1948   "?P \<or> \<not> ?P"}
  1944 
  1949 
  1945   Finally, conversions can also be turned into tactics and then applied to
  1950   Finally, conversions can also be turned into tactics and then applied to
  1946   goal states. This can be done with the help of the function @{ML CONVERSION},
  1951   goal states. This can be done with the help of the function @{ML CONVERSION},
  1947   and also some predefined conversion combinator which traverse a goal
  1952   and also some predefined conversion combinators that traverse a goal
  1948   state. The combinators for the goal state are: @{ML Conv.params_conv} for
  1953   state. The combinators for the goal state are: @{ML Conv.params_conv} for
  1949   going under parameters (i.e.~where goals are of the form @{text "\<And>x. P \<Longrightarrow>
  1954   converting under parameters (i.e.~where goals are of the form @{text "\<And>x. P \<Longrightarrow>
  1950   Q"}); the function @{ML Conv.prems_conv} for applying the conversion to all
  1955   Q"}); the function @{ML Conv.prems_conv} for applying a conversion to all
  1951   premises of a goal, and @{ML Conv.concl_conv} for applying the conversion to
  1956   premises of a goal, and @{ML Conv.concl_conv} for applying a conversion to
  1952   the conclusion of a goal.
  1957   the conclusion of a goal.
  1953 
  1958 
  1954   Assume we want to apply @{ML all_true1_conv} only in the conclusion
  1959   Assume we want to apply @{ML all_true1_conv} only in the conclusion
  1955   of the goal, and @{ML if_true1_conv} should only be applied to the premises.
  1960   of the goal, and @{ML if_true1_conv} should only apply to the premises.
  1956   Here is a tactic doing exactly that:
  1961   Here is a tactic doing exactly that:
  1957 *}
  1962 *}
  1958 
  1963 
  1959 ML{*val true1_tac = CSUBGOAL (fn (goal, i) =>
  1964 ML{*val true1_tac = CSUBGOAL (fn (goal, i) =>
  1960   let 
  1965   let 
  1998   the same assumptions as in \ref{ex:addsimproc}. FIXME: the current solution
  2003   the same assumptions as in \ref{ex:addsimproc}. FIXME: the current solution
  1999   requires some additional functions.
  2004   requires some additional functions.
  2000   \end{exercise}
  2005   \end{exercise}
  2001 
  2006 
  2002   \begin{exercise}
  2007   \begin{exercise}
  2003   Compare which way of rewriting such terms is more efficient. For this
  2008   Compare which way (either Exercise ~\ref{addsimproc} or \ref{ex:addconversion}) of 
  2004   you might have to construct quite large terms.
  2009   rewriting such terms is faster. For this you might have to construct quite 
       
  2010   large terms. Also see Recipe \ref{rec:timing} for information about timing.
  2005   \end{exercise}
  2011   \end{exercise}
  2006 
  2012 
  2007   \begin{readmore}
  2013   \begin{readmore}
  2008   See @{ML_file "Pure/conv.ML"} for more information about conversion combinators. 
  2014   See @{ML_file "Pure/conv.ML"} for more information about conversion combinators. 
  2009   Further conversions are defined in  @{ML_file "Pure/thm.ML"},
  2015   Further conversions are defined in  @{ML_file "Pure/thm.ML"},