ProgTutorial/Solutions.thy
changeset 565 cecd7a941885
parent 562 daf404920ab9
child 567 f7c97e64cc2a
equal deleted inserted replaced
564:6e2479089226 565:cecd7a941885
     1 theory Solutions
     1 theory Solutions
     2 imports First_Steps "Recipes/Timing"
     2 imports First_Steps "Recipes/Timing"
     3 begin
     3 begin
     4 
     4 
     5 chapter {* Solutions to Most Exercises\label{ch:solutions} *}
     5 chapter \<open>Solutions to Most Exercises\label{ch:solutions}\<close>
     6 
     6 
     7 text {* \solution{fun:revsum} *}
     7 text \<open>\solution{fun:revsum}\<close>
     8 
     8 
     9 ML %grayML{*fun rev_sum 
     9 ML %grayML\<open>fun rev_sum 
    10   ((p as Const (@{const_name plus}, _)) $ t $ u) = p $ u $ rev_sum t
    10   ((p as Const (@{const_name plus}, _)) $ t $ u) = p $ u $ rev_sum t
    11   | rev_sum t = t *}
    11   | rev_sum t = t\<close>
    12 
    12 
    13 text {* 
    13 text \<open>
    14   An alternative solution using the function @{ML_ind mk_binop in HOLogic} is:
    14   An alternative solution using the function @{ML_ind mk_binop in HOLogic} is:
    15  *}
    15 \<close>
    16 
    16 
    17 ML %grayML{*fun rev_sum t =
    17 ML %grayML\<open>fun rev_sum t =
    18 let
    18 let
    19   fun dest_sum (Const (@{const_name plus}, _) $ u $ u') = u' :: dest_sum u
    19   fun dest_sum (Const (@{const_name plus}, _) $ u $ u') = u' :: dest_sum u
    20     | dest_sum u = [u]
    20     | dest_sum u = [u]
    21 in
    21 in
    22   foldl1 (HOLogic.mk_binop @{const_name plus}) (dest_sum t)
    22   foldl1 (HOLogic.mk_binop @{const_name plus}) (dest_sum t)
    23 end *}
    23 end\<close>
    24 
    24 
    25 text {* \solution{fun:makesum} *}
    25 text \<open>\solution{fun:makesum}\<close>
    26 
    26 
    27 ML %grayML{*fun make_sum t1 t2 =
    27 ML %grayML\<open>fun make_sum t1 t2 =
    28   HOLogic.mk_nat (HOLogic.dest_nat t1 + HOLogic.dest_nat t2) *}
    28   HOLogic.mk_nat (HOLogic.dest_nat t1 + HOLogic.dest_nat t2)\<close>
    29 
    29 
    30 text {* \solution{fun:killqnt} *}
    30 text \<open>\solution{fun:killqnt}\<close>
    31 
    31 
    32 ML %linenosgray{*val quantifiers = [@{const_name All}, @{const_name Ex}]
    32 ML %linenosgray\<open>val quantifiers = [@{const_name All}, @{const_name Ex}]
    33 
    33 
    34 fun kill_trivial_quantifiers trm =
    34 fun kill_trivial_quantifiers trm =
    35 let
    35 let
    36   fun aux t =
    36   fun aux t =
    37     case t of
    37     case t of
    42     | t1 $ t2 => aux t1 $ aux t2
    42     | t1 $ t2 => aux t1 $ aux t2
    43     | Abs (s, T, t') => Abs (s, T, aux t')
    43     | Abs (s, T, t') => Abs (s, T, aux t')
    44     | _ => t
    44     | _ => t
    45 in 
    45 in 
    46   aux trm
    46   aux trm
    47 end*}
    47 end\<close>
    48 
    48 
    49 text {*
    49 text \<open>
    50   In line 7 we traverse the term, by first checking whether a term is an
    50   In line 7 we traverse the term, by first checking whether a term is an
    51   application of a constant with an abstraction. If the constant stands for
    51   application of a constant with an abstraction. If the constant stands for
    52   a listed quantifier (see Line 1) and the bound variable does not occur
    52   a listed quantifier (see Line 1) and the bound variable does not occur
    53   as a loose bound variable in the body, then we delete the quantifier. 
    53   as a loose bound variable in the body, then we delete the quantifier. 
    54   For this we have to increase all other dangling de Bruijn indices by
    54   For this we have to increase all other dangling de Bruijn indices by
    55   @{text "-1"} to account for the deleted quantifier. An example is 
    55   \<open>-1\<close> to account for the deleted quantifier. An example is 
    56   as follows:
    56   as follows:
    57 
    57 
    58   @{ML_response_fake [display,gray]
    58   @{ML_response_fake [display,gray]
    59   "@{prop \"\<forall>x y z. P x = P z\"}
    59   "@{prop \"\<forall>x y z. P x = P z\"}
    60   |> kill_trivial_quantifiers
    60   |> kill_trivial_quantifiers
    61   |> pretty_term @{context} 
    61   |> pretty_term @{context} 
    62   |> pwriteln"
    62   |> pwriteln"
    63   "\<forall>x z. P x = P z"}
    63   "\<forall>x z. P x = P z"}
    64 *}
    64 \<close>
    65 
    65 
    66 
    66 
    67 
    67 
    68 text {* \solution{fun:makelist} *}
    68 text \<open>\solution{fun:makelist}\<close>
    69 
    69 
    70 ML %grayML{*fun mk_rev_upto i = 
    70 ML %grayML\<open>fun mk_rev_upto i = 
    71   1 upto i
    71   1 upto i
    72   |> map (HOLogic.mk_number @{typ int})
    72   |> map (HOLogic.mk_number @{typ int})
    73   |> HOLogic.mk_list @{typ int}
    73   |> HOLogic.mk_list @{typ int}
    74   |> curry (op $) @{term "rev :: int list \<Rightarrow> int list"}*}
    74   |> curry (op $) @{term "rev :: int list \<Rightarrow> int list"}\<close>
    75 
    75 
    76 text {* \solution{ex:debruijn} *}
    76 text \<open>\solution{ex:debruijn}\<close>
    77 
    77 
    78 ML %grayML{*fun P n = @{term "P::nat \<Rightarrow> bool"} $ (HOLogic.mk_number @{typ "nat"} n) 
    78 ML %grayML\<open>fun P n = @{term "P::nat \<Rightarrow> bool"} $ (HOLogic.mk_number @{typ "nat"} n) 
    79 
    79 
    80 fun rhs 1 = P 1
    80 fun rhs 1 = P 1
    81   | rhs n = HOLogic.mk_conj (P n, rhs (n - 1))
    81   | rhs n = HOLogic.mk_conj (P n, rhs (n - 1))
    82 
    82 
    83 fun lhs 1 n = HOLogic.mk_imp (HOLogic.mk_eq (P 1, P n), rhs n)
    83 fun lhs 1 n = HOLogic.mk_imp (HOLogic.mk_eq (P 1, P n), rhs n)
    84   | lhs m n = HOLogic.mk_conj (HOLogic.mk_imp 
    84   | lhs m n = HOLogic.mk_conj (HOLogic.mk_imp 
    85                  (HOLogic.mk_eq (P (m - 1), P m), rhs n), lhs (m - 1) n)
    85                  (HOLogic.mk_eq (P (m - 1), P m), rhs n), lhs (m - 1) n)
    86 
    86 
    87 fun de_bruijn n =
    87 fun de_bruijn n =
    88   HOLogic.mk_Trueprop (HOLogic.mk_imp (lhs n n, rhs n))*}
    88   HOLogic.mk_Trueprop (HOLogic.mk_imp (lhs n n, rhs n))\<close>
    89 
    89 
    90 text {* \solution{ex:scancmts} *}
    90 text \<open>\solution{ex:scancmts}\<close>
    91 
    91 
    92 ML %grayML{*val any = Scan.one (Symbol.not_eof)
    92 ML %grayML\<open>val any = Scan.one (Symbol.not_eof)
    93 
    93 
    94 val scan_cmt =
    94 val scan_cmt =
    95 let
    95 let
    96   val begin_cmt = Scan.this_string "(*" 
    96   val begin_cmt = Scan.this_string "(*" 
    97   val end_cmt = Scan.this_string "*)"
    97   val end_cmt = Scan.this_string "*)"
   101 end
   101 end
   102 
   102 
   103 val parser = Scan.repeat (scan_cmt || any)
   103 val parser = Scan.repeat (scan_cmt || any)
   104 
   104 
   105 val scan_all =
   105 val scan_all =
   106       Scan.finite Symbol.stopper parser >> implode #> fst *}
   106       Scan.finite Symbol.stopper parser >> implode #> fst\<close>
   107 
   107 
   108 text {*
   108 text \<open>
   109   By using @{text "#> fst"} in the last line, the function 
   109   By using \<open>#> fst\<close> in the last line, the function 
   110   @{ML scan_all} retruns a string, instead of the pair a parser would
   110   @{ML scan_all} retruns a string, instead of the pair a parser would
   111   normally return. For example:
   111   normally return. For example:
   112 
   112 
   113   @{ML_response [display,gray]
   113   @{ML_response [display,gray]
   114 "let
   114 "let
   116   val input2 = (Symbol.explode \"foo (*test*) bar (*test*)\")
   116   val input2 = (Symbol.explode \"foo (*test*) bar (*test*)\")
   117 in
   117 in
   118   (scan_all input1, scan_all input2)
   118   (scan_all input1, scan_all input2)
   119 end"
   119 end"
   120 "(\"foo bar\", \"foo (**test**) bar (**test**)\")"}
   120 "(\"foo bar\", \"foo (**test**) bar (**test**)\")"}
   121 *}
   121 \<close>
   122 
   122 
   123 text {* \solution{ex:contextfree} *}
   123 text \<open>\solution{ex:contextfree}\<close>
   124 
   124 
   125 ML %grayML{*datatype expr = 
   125 ML %grayML\<open>datatype expr = 
   126    Number of int
   126    Number of int
   127  | Mult of expr * expr 
   127  | Mult of expr * expr 
   128  | Add of expr * expr
   128  | Add of expr * expr
   129 
   129 
   130 fun parse_basic xs =
   130 fun parse_basic xs =
   133 and parse_factor xs =
   133 and parse_factor xs =
   134   (parse_basic --| Parse.$$$ "*" -- parse_factor >> Mult 
   134   (parse_basic --| Parse.$$$ "*" -- parse_factor >> Mult 
   135    || parse_basic) xs
   135    || parse_basic) xs
   136 and parse_expr xs =
   136 and parse_expr xs =
   137   (parse_factor --| Parse.$$$ "+" -- parse_expr >> Add 
   137   (parse_factor --| Parse.$$$ "+" -- parse_expr >> Add 
   138    || parse_factor) xs*}
   138    || parse_factor) xs\<close>
   139 
   139 
   140 
   140 
   141 text {* \solution{ex:dyckhoff} *}
   141 text \<open>\solution{ex:dyckhoff}\<close>
   142 
   142 
   143 text {* 
   143 text \<open>
   144   The axiom rule can be implemented with the function @{ML assume_tac}. The other
   144   The axiom rule can be implemented with the function @{ML assume_tac}. The other
   145   rules correspond to the theorems:
   145   rules correspond to the theorems:
   146 
   146 
   147   \begin{center}
   147   \begin{center}
   148   \begin{tabular}{cc}
   148   \begin{tabular}{cc}
   162   \end{tabular}
   162   \end{tabular}
   163   \end{tabular}
   163   \end{tabular}
   164   \end{center}
   164   \end{center}
   165 
   165 
   166   For the other rules we need to prove the following lemmas.
   166   For the other rules we need to prove the following lemmas.
   167 *}
   167 \<close>
   168 
   168 
   169 lemma impE1:
   169 lemma impE1:
   170   shows "\<lbrakk>A \<longrightarrow> B; A; B \<Longrightarrow> R\<rbrakk> \<Longrightarrow> R"
   170   shows "\<lbrakk>A \<longrightarrow> B; A; B \<Longrightarrow> R\<rbrakk> \<Longrightarrow> R"
   171   by iprover
   171   by iprover
   172 
   172 
   175   and   "\<lbrakk>(C \<or> D) \<longrightarrow> B; \<lbrakk>C \<longrightarrow> B; D \<longrightarrow> B\<rbrakk> \<Longrightarrow> R\<rbrakk> \<Longrightarrow> R"
   175   and   "\<lbrakk>(C \<or> D) \<longrightarrow> B; \<lbrakk>C \<longrightarrow> B; D \<longrightarrow> B\<rbrakk> \<Longrightarrow> R\<rbrakk> \<Longrightarrow> R"
   176   and   "\<lbrakk>(C \<longrightarrow> D) \<longrightarrow> B; D \<longrightarrow> B \<Longrightarrow> C \<longrightarrow> D; B \<Longrightarrow> R\<rbrakk> \<Longrightarrow> R"
   176   and   "\<lbrakk>(C \<longrightarrow> D) \<longrightarrow> B; D \<longrightarrow> B \<Longrightarrow> C \<longrightarrow> D; B \<Longrightarrow> R\<rbrakk> \<Longrightarrow> R"
   177   and   "\<lbrakk>(C = D) \<longrightarrow> B; (C \<longrightarrow> D) \<longrightarrow> ((D \<longrightarrow> C) \<longrightarrow> B) \<Longrightarrow> R\<rbrakk> \<Longrightarrow> R"
   177   and   "\<lbrakk>(C = D) \<longrightarrow> B; (C \<longrightarrow> D) \<longrightarrow> ((D \<longrightarrow> C) \<longrightarrow> B) \<Longrightarrow> R\<rbrakk> \<Longrightarrow> R"
   178   by iprover+
   178   by iprover+
   179 
   179 
   180 text {*
   180 text \<open>
   181   Now the tactic which applies a single rule can be implemented
   181   Now the tactic which applies a single rule can be implemented
   182   as follows.
   182   as follows.
   183 *}
   183 \<close>
   184 
   184 
   185 ML %linenosgray{*fun apply_tac ctxt =
   185 ML %linenosgray\<open>fun apply_tac ctxt =
   186 let
   186 let
   187   val intros = @{thms conjI disjI1 disjI2 impI iffI}
   187   val intros = @{thms conjI disjI1 disjI2 impI iffI}
   188   val elims = @{thms FalseE conjE disjE iffE impE2}
   188   val elims = @{thms FalseE conjE disjE iffE impE2}
   189 in
   189 in
   190   assume_tac ctxt
   190   assume_tac ctxt
   191   ORELSE' resolve_tac ctxt intros
   191   ORELSE' resolve_tac ctxt intros
   192   ORELSE' eresolve_tac ctxt elims
   192   ORELSE' eresolve_tac ctxt elims
   193   ORELSE' (eresolve_tac ctxt [@{thm impE1}] THEN' assume_tac ctxt)
   193   ORELSE' (eresolve_tac ctxt [@{thm impE1}] THEN' assume_tac ctxt)
   194 end*}
   194 end\<close>
   195 
   195 
   196 text {*
   196 text \<open>
   197   In Line 11 we apply the rule @{thm [source] impE1} in concjunction 
   197   In Line 11 we apply the rule @{thm [source] impE1} in concjunction 
   198   with @{ML assume_tac} in order to reduce the number of possibilities that
   198   with @{ML assume_tac} in order to reduce the number of possibilities that
   199   need to be explored. You can use the tactic as follows.
   199   need to be explored. You can use the tactic as follows.
   200 *}
   200 \<close>
   201 
   201 
   202 lemma
   202 lemma
   203   shows "((((P \<longrightarrow> Q) \<longrightarrow> P) \<longrightarrow> P) \<longrightarrow> Q) \<longrightarrow> Q"
   203   shows "((((P \<longrightarrow> Q) \<longrightarrow> P) \<longrightarrow> P) \<longrightarrow> Q) \<longrightarrow> Q"
   204 apply(tactic {* (DEPTH_SOLVE o apply_tac @{context}) 1 *})
   204 apply(tactic \<open>(DEPTH_SOLVE o apply_tac @{context}) 1\<close>)
   205 done
   205 done
   206 
   206 
   207 text {*
   207 text \<open>
   208   We can use the tactic to prove or disprove automatically the
   208   We can use the tactic to prove or disprove automatically the
   209   de Bruijn formulae from Exercise \ref{ex:debruijn}.
   209   de Bruijn formulae from Exercise \ref{ex:debruijn}.
   210 *}
   210 \<close>
   211 
   211 
   212 ML %grayML{*fun de_bruijn_prove ctxt n =
   212 ML %grayML\<open>fun de_bruijn_prove ctxt n =
   213 let 
   213 let 
   214   val goal = HOLogic.mk_Trueprop (HOLogic.mk_imp (lhs n n, rhs n))
   214   val goal = HOLogic.mk_Trueprop (HOLogic.mk_imp (lhs n n, rhs n))
   215 in
   215 in
   216   Goal.prove ctxt ["P"] [] goal
   216   Goal.prove ctxt ["P"] [] goal
   217    (fn _ => (DEPTH_SOLVE o apply_tac ctxt) 1)
   217    (fn _ => (DEPTH_SOLVE o apply_tac ctxt) 1)
   218 end*}
   218 end\<close>
   219 
   219 
   220 text {* 
   220 text \<open>
   221   You can use this function to prove de Bruijn formulae.
   221   You can use this function to prove de Bruijn formulae.
   222 *}
   222 \<close>
   223 
   223 
   224 ML %grayML{*de_bruijn_prove @{context} 3 *}
   224 ML %grayML\<open>de_bruijn_prove @{context} 3\<close>
   225 
   225 
   226 text {* \solution{ex:addsimproc} *}
   226 text \<open>\solution{ex:addsimproc}\<close>
   227 
   227 
   228 ML %grayML{*fun dest_sum term =
   228 ML %grayML\<open>fun dest_sum term =
   229   case term of 
   229   case term of 
   230     (@{term "(+):: nat \<Rightarrow> nat \<Rightarrow> nat"} $ t1 $ t2) =>
   230     (@{term "(+):: nat \<Rightarrow> nat \<Rightarrow> nat"} $ t1 $ t2) =>
   231         (snd (HOLogic.dest_number t1), snd (HOLogic.dest_number t2))
   231         (snd (HOLogic.dest_number t1), snd (HOLogic.dest_number t2))
   232   | _ => raise TERM ("dest_sum", [term])
   232   | _ => raise TERM ("dest_sum", [term])
   233 
   233 
   243 let 
   243 let 
   244   val t' = Thm.term_of t
   244   val t' = Thm.term_of t
   245 in
   245 in
   246   SOME (get_sum_thm ctxt t' (dest_sum t'))
   246   SOME (get_sum_thm ctxt t' (dest_sum t'))
   247   handle TERM _ => NONE
   247   handle TERM _ => NONE
   248 end*}
   248 end\<close>
   249 
   249 
   250 text {* The setup for the simproc is *}
   250 text \<open>The setup for the simproc is\<close>
   251 
   251 
   252 simproc_setup %gray add_sp ("t1 + t2") = {* K add_sp_aux *}
   252 simproc_setup %gray add_sp ("t1 + t2") = \<open>K add_sp_aux\<close>
   253  
   253  
   254 text {* and a test case is the lemma *}
   254 text \<open>and a test case is the lemma\<close>
   255 
   255 
   256 lemma "P (Suc (99 + 1)) ((0 + 0)::nat) (Suc (3 + 3 + 3)) ((4 + 1)::nat)"
   256 lemma "P (Suc (99 + 1)) ((0 + 0)::nat) (Suc (3 + 3 + 3)) ((4 + 1)::nat)"
   257   apply(tactic {* simp_tac (put_simpset HOL_basic_ss @{context} addsimprocs [@{simproc add_sp}]) 1 *})
   257   apply(tactic \<open>simp_tac (put_simpset HOL_basic_ss @{context} addsimprocs [@{simproc add_sp}]) 1\<close>)
   258 txt {* 
   258 txt \<open>
   259   where the simproc produces the goal state
   259   where the simproc produces the goal state
   260   
   260   
   261   \begin{minipage}{\textwidth}
   261   \begin{minipage}{\textwidth}
   262   @{subgoals [display]}
   262   @{subgoals [display]}
   263   \end{minipage}\bigskip
   263   \end{minipage}\bigskip
   264 *}(*<*)oops(*>*)
   264 \<close>(*<*)oops(*>*)
   265 
   265 
   266 text {* \solution{ex:addconversion} *}
   266 text \<open>\solution{ex:addconversion}\<close>
   267 
   267 
   268 text {*
   268 text \<open>
   269   The following code assumes the function @{ML dest_sum} from the previous
   269   The following code assumes the function @{ML dest_sum} from the previous
   270   exercise.
   270   exercise.
   271 *}
   271 \<close>
   272 
   272 
   273 ML %grayML{*fun add_simple_conv ctxt ctrm =
   273 ML %grayML\<open>fun add_simple_conv ctxt ctrm =
   274 let
   274 let
   275   val trm = Thm.term_of ctrm
   275   val trm = Thm.term_of ctrm
   276 in
   276 in
   277   case trm of
   277   case trm of
   278      @{term "(+)::nat \<Rightarrow> nat \<Rightarrow> nat"} $ _ $ _ => 
   278      @{term "(+)::nat \<Rightarrow> nat \<Rightarrow> nat"} $ _ $ _ => 
   280     | _ => Conv.all_conv ctrm
   280     | _ => Conv.all_conv ctrm
   281 end
   281 end
   282 
   282 
   283 val add_conv = Conv.bottom_conv add_simple_conv
   283 val add_conv = Conv.bottom_conv add_simple_conv
   284 
   284 
   285 fun add_tac ctxt = CONVERSION (add_conv ctxt)*}
   285 fun add_tac ctxt = CONVERSION (add_conv ctxt)\<close>
   286 
   286 
   287 text {*
   287 text \<open>
   288   A test case for this conversion is as follows
   288   A test case for this conversion is as follows
   289 *}
   289 \<close>
   290 
   290 
   291 lemma "P (Suc (99 + 1)) ((0 + 0)::nat) (Suc (3 + 3 + 3)) ((4 + 1)::nat)"
   291 lemma "P (Suc (99 + 1)) ((0 + 0)::nat) (Suc (3 + 3 + 3)) ((4 + 1)::nat)"
   292   apply(tactic {* add_tac @{context} 1 *})?
   292   apply(tactic \<open>add_tac @{context} 1\<close>)?
   293 txt {* 
   293 txt \<open>
   294   where it produces the goal state
   294   where it produces the goal state
   295   
   295   
   296   \begin{minipage}{\textwidth}
   296   \begin{minipage}{\textwidth}
   297   @{subgoals [display]}
   297   @{subgoals [display]}
   298   \end{minipage}\bigskip
   298   \end{minipage}\bigskip
   299 *}(*<*)oops(*>*)
   299 \<close>(*<*)oops(*>*)
   300 
   300 
   301 text {* \solution{ex:compare} *}
   301 text \<open>\solution{ex:compare}\<close>
   302 
   302 
   303 text {* 
   303 text \<open>
   304   We use the timing function @{ML timing_wrapper} from Recipe~\ref{rec:timing}.
   304   We use the timing function @{ML timing_wrapper} from Recipe~\ref{rec:timing}.
   305   To measure any difference between the simproc and conversion, we will create 
   305   To measure any difference between the simproc and conversion, we will create 
   306   mechanically terms involving additions and then set up a goal to be 
   306   mechanically terms involving additions and then set up a goal to be 
   307   simplified. We have to be careful to set up the goal so that
   307   simplified. We have to be careful to set up the goal so that
   308   other parts of the simplifier do not interfere. For this we construct an
   308   other parts of the simplifier do not interfere. For this we construct an
   310   the help of ``\isacommand{sorry}'', that is the method @{ML Skip_Proof.cheat_tac}
   310   the help of ``\isacommand{sorry}'', that is the method @{ML Skip_Proof.cheat_tac}
   311 
   311 
   312   For constructing test cases, we first define a function that returns a 
   312   For constructing test cases, we first define a function that returns a 
   313   complete binary tree whose leaves are numbers and the nodes are 
   313   complete binary tree whose leaves are numbers and the nodes are 
   314   additions.
   314   additions.
   315 *}
   315 \<close>
   316 
   316 
   317 ML %grayML{*fun term_tree n =
   317 ML %grayML\<open>fun term_tree n =
   318 let
   318 let
   319   val count = Unsynchronized.ref 0; 
   319   val count = Unsynchronized.ref 0; 
   320 
   320 
   321   fun term_tree_aux n =
   321   fun term_tree_aux n =
   322     case n of
   322     case n of
   323       0 => (count := !count + 1; HOLogic.mk_number @{typ nat} (!count))
   323       0 => (count := !count + 1; HOLogic.mk_number @{typ nat} (!count))
   324     | _ => Const (@{const_name "plus"}, @{typ "nat\<Rightarrow>nat\<Rightarrow>nat"}) 
   324     | _ => Const (@{const_name "plus"}, @{typ "nat\<Rightarrow>nat\<Rightarrow>nat"}) 
   325              $ (term_tree_aux (n - 1)) $ (term_tree_aux (n - 1))
   325              $ (term_tree_aux (n - 1)) $ (term_tree_aux (n - 1))
   326 in
   326 in
   327   term_tree_aux n
   327   term_tree_aux n
   328 end*}
   328 end\<close>
   329 
   329 
   330 text {*
   330 text \<open>
   331   This function generates for example:
   331   This function generates for example:
   332 
   332 
   333   @{ML_response_fake [display,gray] 
   333   @{ML_response_fake [display,gray] 
   334   "pwriteln (pretty_term @{context} (term_tree 2))" 
   334   "pwriteln (pretty_term @{context} (term_tree 2))" 
   335   "(1 + 2) + (3 + 4)"} 
   335   "(1 + 2) + (3 + 4)"} 
   336 
   336 
   337   The next function constructs a goal of the form @{text "P \<dots>"} with a term 
   337   The next function constructs a goal of the form \<open>P \<dots>\<close> with a term 
   338   produced by @{ML term_tree} filled in.
   338   produced by @{ML term_tree} filled in.
   339 *}
   339 \<close>
   340 
   340 
   341 ML %grayML{*fun goal n = HOLogic.mk_Trueprop (@{term "P::nat\<Rightarrow> bool"} $ (term_tree n))*}
   341 ML %grayML\<open>fun goal n = HOLogic.mk_Trueprop (@{term "P::nat\<Rightarrow> bool"} $ (term_tree n))\<close>
   342 
   342 
   343 text {*
   343 text \<open>
   344   Note that the goal needs to be wrapped in a @{term "Trueprop"}. Next we define
   344   Note that the goal needs to be wrapped in a @{term "Trueprop"}. Next we define
   345   two tactics, @{text "c_tac"} and @{text "s_tac"}, for the conversion and simproc,
   345   two tactics, \<open>c_tac\<close> and \<open>s_tac\<close>, for the conversion and simproc,
   346   respectively. The idea is to first apply the conversion (respectively simproc) and 
   346   respectively. The idea is to first apply the conversion (respectively simproc) and 
   347   then prove the remaining goal using @{ML "cheat_tac" in Skip_Proof}.
   347   then prove the remaining goal using @{ML "cheat_tac" in Skip_Proof}.
   348 *}
   348 \<close>
   349 
   349 
   350 ML Skip_Proof.cheat_tac
   350 ML Skip_Proof.cheat_tac
   351 
   351 
   352 ML %grayML{*local
   352 ML %grayML\<open>local
   353   fun mk_tac ctxt tac = 
   353   fun mk_tac ctxt tac = 
   354         timing_wrapper (EVERY1 [tac, Skip_Proof.cheat_tac ctxt])
   354         timing_wrapper (EVERY1 [tac, Skip_Proof.cheat_tac ctxt])
   355 in
   355 in
   356   fun c_tac ctxt = mk_tac ctxt (add_tac ctxt) 
   356   fun c_tac ctxt = mk_tac ctxt (add_tac ctxt) 
   357   fun s_tac ctxt = mk_tac ctxt (simp_tac 
   357   fun s_tac ctxt = mk_tac ctxt (simp_tac 
   358     (put_simpset HOL_basic_ss ctxt addsimprocs [@{simproc add_sp}]))
   358     (put_simpset HOL_basic_ss ctxt addsimprocs [@{simproc add_sp}]))
   359 end*}
   359 end\<close>
   360 
   360 
   361 text {*
   361 text \<open>
   362   This is all we need to let the conversion run against the simproc:
   362   This is all we need to let the conversion run against the simproc:
   363 *}
   363 \<close>
   364 
   364 
   365 ML %grayML{*val _ = Goal.prove @{context} [] [] (goal 8) (fn {context, ...} => c_tac context)
   365 ML %grayML\<open>val _ = Goal.prove @{context} [] [] (goal 8) (fn {context, ...} => c_tac context)
   366 val _ = Goal.prove @{context} [] [] (goal 8) (fn {context, ...} => s_tac context)*}
   366 val _ = Goal.prove @{context} [] [] (goal 8) (fn {context, ...} => s_tac context)\<close>
   367 
   367 
   368 text {*
   368 text \<open>
   369   If you do the exercise, you can see that both ways of simplifying additions
   369   If you do the exercise, you can see that both ways of simplifying additions
   370   perform relatively similar with perhaps some advantages for the
   370   perform relatively similar with perhaps some advantages for the
   371   simproc. That means the simplifier, even if much more complicated than
   371   simproc. That means the simplifier, even if much more complicated than
   372   conversions, is quite efficient for tasks it is designed for. It usually does not
   372   conversions, is quite efficient for tasks it is designed for. It usually does not
   373   make sense to implement general-purpose rewriting using
   373   make sense to implement general-purpose rewriting using
   374   conversions. Conversions only have clear advantages in special situations:
   374   conversions. Conversions only have clear advantages in special situations:
   375   for example if you need to have control over innermost or outermost
   375   for example if you need to have control over innermost or outermost
   376   rewriting, or when rewriting rules are lead to non-termination.
   376   rewriting, or when rewriting rules are lead to non-termination.
   377 *}
   377 \<close>
   378 
   378 
   379 end
   379 end