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"}, |