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 "*)" |
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 |