2202 "(True \<and> Q \<equiv> Q, P \<or> True \<and> Q \<equiv> P \<or> True \<and> Q)"} |
2202 "(True \<and> Q \<equiv> Q, P \<or> True \<and> Q \<equiv> P \<or> True \<and> Q)"} |
2203 |
2203 |
2204 Here the conversion of @{thm [source] true_conj1} only applies |
2204 Here the conversion of @{thm [source] true_conj1} only applies |
2205 in the first case, but fails in the second. The whole conversion |
2205 in the first case, but fails in the second. The whole conversion |
2206 does not fail, however, because the combinator @{ML else_conv in Conv} will then |
2206 does not fail, however, because the combinator @{ML else_conv in Conv} will then |
2207 try out @{ML all_conv in Conv}, which always succeeds. |
2207 try out @{ML all_conv in Conv}, which always succeeds. The same |
2208 |
2208 behaviour can also be achieved with conversion combinator @{ML_ind try_conv in Conv}. |
2209 The conversion combinator @{ML_ind try_conv in Conv} constructs a conversion |
|
2210 which is tried out on a term, but in case of failure just does nothing. |
|
2211 For example |
2209 For example |
2212 |
2210 |
2213 @{ML_response_fake [display,gray] |
2211 @{ML_response_fake [display,gray] |
2214 "let |
2212 "let |
2215 val conv = Conv.try_conv (Conv.rewr_conv @{thm true_conj1}) |
2213 val conv = Conv.try_conv (Conv.rewr_conv @{thm true_conj1}) |
2216 val ctrm = @{cterm \"True \<or> P\"} |
2214 val ctrm = @{cterm \"True \<or> P\"} |
2217 in |
2215 in |
2218 conv ctrm |
2216 conv ctrm |
2219 end" |
2217 end" |
2220 "True \<or> P \<equiv> True \<or> P"} |
2218 "True \<or> P \<equiv> True \<or> P"} |
|
2219 |
|
2220 Rewriting with more than one theorem can be done using the function |
|
2221 @{ML_ind rewrs_conv in More_Conv} from the structure @{ML_struct More_Conv}. |
|
2222 |
2221 |
2223 |
2222 Apart from the function @{ML beta_conversion in Thm}, which is able to fully |
2224 Apart from the function @{ML beta_conversion in Thm}, which is able to fully |
2223 beta-normalise a term, the conversions so far are restricted in that they |
2225 beta-normalise a term, the conversions so far are restricted in that they |
2224 only apply to the outer-most level of a @{ML_type cterm}. In what follows we |
2226 only apply to the outer-most level of a @{ML_type cterm}. In what follows we |
2225 will lift this restriction. The combinators @{ML_ind fun_conv in Conv} |
2227 will lift this restriction. The combinators @{ML_ind fun_conv in Conv} |
2267 We can now apply all these functions in a conversion that recursively |
2269 We can now apply all these functions in a conversion that recursively |
2268 descends a term and applies a ``@{thm [source] true_conj1}''-conversion |
2270 descends a term and applies a ``@{thm [source] true_conj1}''-conversion |
2269 in all possible positions. |
2271 in all possible positions. |
2270 *} |
2272 *} |
2271 |
2273 |
2272 ML %linenosgray{*fun all_true1_conv ctxt ctrm = |
2274 ML %linenosgray{*fun true_conj1_conv ctxt ctrm = |
2273 case (Thm.term_of ctrm) of |
2275 case (Thm.term_of ctrm) of |
2274 @{term "op \<and>"} $ @{term True} $ _ => |
2276 @{term "op \<and>"} $ @{term True} $ _ => |
2275 (Conv.arg_conv (all_true1_conv ctxt) then_conv |
2277 (Conv.arg_conv (true_conj1_conv ctxt) then_conv |
2276 Conv.rewr_conv @{thm true_conj1}) ctrm |
2278 Conv.rewr_conv @{thm true_conj1}) ctrm |
2277 | _ $ _ => Conv.comb_conv (all_true1_conv ctxt) ctrm |
2279 | _ $ _ => Conv.comb_conv (true_conj1_conv ctxt) ctrm |
2278 | Abs _ => Conv.abs_conv (fn (_, ctxt) => all_true1_conv ctxt) ctxt ctrm |
2280 | Abs _ => Conv.abs_conv (fn (_, ctxt) => true_conj1_conv ctxt) ctxt ctrm |
2279 | _ => Conv.all_conv ctrm*} |
2281 | _ => Conv.all_conv ctrm*} |
2280 |
2282 |
2281 text {* |
2283 text {* |
2282 This function ``fires'' if the terms is of the form @{text "(True \<and> \<dots>)"}. |
2284 This function ``fires'' if the terms is of the form @{text "(True \<and> \<dots>)"}. |
2283 It descends under applications (Line 6 and 7) and abstractions |
2285 It descends under applications (Line 6 and 7) and abstractions |
2286 to be able to pattern-match the term. To see this |
2288 to be able to pattern-match the term. To see this |
2287 conversion in action, consider the following example: |
2289 conversion in action, consider the following example: |
2288 |
2290 |
2289 @{ML_response_fake [display,gray] |
2291 @{ML_response_fake [display,gray] |
2290 "let |
2292 "let |
2291 val conv = all_true1_conv @{context} |
2293 val conv = true_conj1_conv @{context} |
2292 val ctrm = @{cterm \"distinct [1, x] \<longrightarrow> True \<and> 1 \<noteq> x\"} |
2294 val ctrm = @{cterm \"distinct [1::nat, x] \<longrightarrow> True \<and> 1 \<noteq> x\"} |
2293 in |
2295 in |
2294 conv ctrm |
2296 conv ctrm |
2295 end" |
2297 end" |
2296 "distinct [1, x] \<longrightarrow> True \<and> 1 \<noteq> x \<equiv> distinct [1, x] \<longrightarrow> 1 \<noteq> x"} |
2298 "distinct [1, x] \<longrightarrow> True \<and> 1 \<noteq> x \<equiv> distinct [1, x] \<longrightarrow> 1 \<noteq> x"} |
|
2299 *} |
|
2300 |
|
2301 text {* |
|
2302 Conversions that traverse terms, like @{ML true_conj1_conv} above, can be |
|
2303 implemented more succinctly with the combinators @{ML_ind bottom_conv in |
|
2304 More_Conv} and @{ML_ind top_conv in More_Conv}. For example: |
|
2305 *} |
|
2306 |
|
2307 ML{*fun true_conj1_conv ctxt = |
|
2308 let |
|
2309 val conv = Conv.try_conv (Conv.rewr_conv @{thm true_conj1}) |
|
2310 in |
|
2311 More_Conv.bottom_conv (K conv) ctxt |
|
2312 end*} |
|
2313 |
|
2314 text {* |
|
2315 The function @{ML bottom_conv in More_Conv} traverses first the the term and |
|
2316 on the ``way down'' applies the conversion, whereas @{ML top_conv in |
|
2317 More_Conv} applies the on the ``way up''. To see the difference, |
|
2318 assume the following two meta-equations. |
|
2319 *} |
|
2320 |
|
2321 lemma conj_assoc: |
|
2322 fixes A B C::bool |
|
2323 shows "A \<and> (B \<and> C) \<equiv> (A \<and> B) \<and> C" |
|
2324 and "(A \<and> B) \<and> C \<equiv> A \<and> (B \<and> C)" |
|
2325 by simp_all |
|
2326 |
|
2327 text {* |
|
2328 and the @{ML_type cterm} @{text "(a \<and> (b \<and> c)) \<and> d"}. The reader should |
|
2329 pause for a moment to be convinced that rewriting top-down and bottom-up |
|
2330 according to the lemma produces two results. |
|
2331 |
|
2332 @{ML_response_fake [display, gray] |
|
2333 "let |
|
2334 val ctxt = @{context} |
|
2335 val conv = Conv.try_conv (More_Conv.rewrs_conv @{thms conj_assoc}) |
|
2336 val conv_top = More_Conv.top_conv (K conv) ctxt |
|
2337 val conv_bot = More_Conv.bottom_conv (K conv) ctxt |
|
2338 val ctrm = @{cterm \"(a \<and> (b \<and> c)) \<and> d\"} |
|
2339 in |
|
2340 (conv_top ctrm, conv_bot ctrm) |
|
2341 end" |
|
2342 "(\"(a \<and> (b \<and> c)) \<and> d \<equiv> a \<and> (b \<and> (c \<and> d))\", |
|
2343 \"(a \<and> (b \<and> c)) \<and> d \<equiv> (a \<and> b) \<and> (c \<and> d)\")"} |
2297 |
2344 |
2298 To see how much control you have about rewriting by using conversions, let us |
2345 To see how much control you have about rewriting by using conversions, let us |
2299 make the task a bit more complicated by rewriting according to the rule |
2346 make the task a bit more complicated by rewriting according to the rule |
2300 @{text true_conj1}, but only in the first arguments of @{term If}s. Then |
2347 @{text true_conj1}, but only in the first arguments of @{term If}s. Then |
2301 the conversion should be as follows. |
2348 the conversion should be as follows. |
2302 *} |
2349 *} |
2303 |
2350 |
2304 ML{*fun if_true1_conv ctxt ctrm = |
2351 ML{*fun if_true1_simple_conv ctxt ctrm = |
2305 case Thm.term_of ctrm of |
2352 case Thm.term_of ctrm of |
2306 Const (@{const_name If}, _) $ _ => |
2353 Const (@{const_name If}, _) $ _ => |
2307 Conv.arg_conv (all_true1_conv ctxt) ctrm |
2354 Conv.arg_conv (true_conj1_conv ctxt) ctrm |
2308 | _ $ _ => Conv.comb_conv (if_true1_conv ctxt) ctrm |
2355 | _ => Conv.no_conv ctrm |
2309 | Abs _ => Conv.abs_conv (fn (_, ctxt) => if_true1_conv ctxt) ctxt ctrm |
2356 |
2310 | _ => Conv.all_conv ctrm *} |
2357 val if_true1_conv = More_Conv.top_sweep_conv if_true1_simple_conv*} |
2311 |
2358 |
2312 text {* |
2359 text {* |
2313 Here is an example for this conversion: |
2360 In the first function we only treat the top-most redex and also only the |
|
2361 success case and otherwise return @{ML no_conv in Conv}. To apply this |
|
2362 conversion inside a term, we use in the last line the combinator @{ML_ind |
|
2363 top_sweep_conv in More_Conv}, which traverses the term starting from the |
|
2364 root and applies it to all the redexes on the way, but stops in a branch as |
|
2365 soon as it found one redex.\footnote{\bf Fixme: Check with Sascha whether |
|
2366 the conversion stops after a single success case, or stops in each branch |
|
2367 after a success case.} Here is an example for this conversion: |
|
2368 |
2314 |
2369 |
2315 @{ML_response_fake [display,gray] |
2370 @{ML_response_fake [display,gray] |
2316 "let |
2371 "let |
2317 val conv = if_true1_conv @{context} |
2372 val ctrm = @{cterm \"if P (True \<and> 1 \<noteq> (2::nat)) |
2318 val ctrm = |
2373 then True \<and> True else True \<and> False\"} |
2319 @{cterm \"if P (True \<and> 1 \<noteq> 2) then True \<and> True else True \<and> False\"} |
|
2320 in |
2374 in |
2321 conv ctrm |
2375 if_true1_conv @{context} ctrm |
2322 end" |
2376 end" |
2323 "if P (True \<and> 1 \<noteq> 2) then True \<and> True else True \<and> False |
2377 "if P (True \<and> 1 \<noteq> 2) then True \<and> True else True \<and> False |
2324 \<equiv> if P (1 \<noteq> 2) then True \<and> True else True \<and> False"} |
2378 \<equiv> if P (1 \<noteq> 2) then True \<and> True else True \<and> False"} |
2325 *} |
2379 *} |
2326 |
2380 |
2327 text {* |
2381 text {* |
2328 So far we only applied conversions to @{ML_type cterm}s. Conversions can, however, |
2382 So far we only applied conversions to @{ML_type cterm}s. Conversions can, however, |
2329 also work on theorems using the function @{ML_ind fconv_rule in Conv}. As an example, |
2383 also work on theorems using the function @{ML_ind fconv_rule in Conv}. As an example, |
2330 consider the conversion @{ML all_true1_conv} and the lemma: |
2384 consider the conversion @{ML true_conj1_conv} and the lemma: |
2331 *} |
2385 *} |
2332 |
2386 |
2333 lemma foo_test: |
2387 lemma foo_test: |
2334 shows "P \<or> (True \<and> \<not>P)" by simp |
2388 shows "P \<or> (True \<and> \<not>P)" by simp |
2335 |
2389 |
2336 text {* |
2390 text {* |
2337 Using the conversion @{ML all_true1_conv} you can transform this theorem into a |
2391 Using the conversion @{ML true_conj1_conv} you can transform this theorem into a |
2338 new theorem as follows |
2392 new theorem as follows |
2339 |
2393 |
2340 @{ML_response_fake [display,gray] |
2394 @{ML_response_fake [display,gray] |
2341 "let |
2395 "let |
2342 val conv = Conv.fconv_rule (all_true1_conv @{context}) |
2396 val conv = Conv.fconv_rule (true_conj1_conv @{context}) |
2343 val thm = @{thm foo_test} |
2397 val thm = @{thm foo_test} |
2344 in |
2398 in |
2345 conv thm |
2399 conv thm |
2346 end" |
2400 end" |
2347 "?P \<or> \<not> ?P"} |
2401 "?P \<or> \<not> ?P"} |
2361 |
2415 |
2362 \item @{ML_ind concl_conv in Conv} for applying a conversion to the |
2416 \item @{ML_ind concl_conv in Conv} for applying a conversion to the |
2363 conclusion of a goal. |
2417 conclusion of a goal. |
2364 \end{itemize} |
2418 \end{itemize} |
2365 |
2419 |
2366 Assume we want to apply @{ML all_true1_conv} only in the conclusion |
2420 Assume we want to apply @{ML true_conj1_conv} only in the conclusion |
2367 of the goal, and @{ML if_true1_conv} should only apply to the premises. |
2421 of the goal, and @{ML if_true1_conv} should only apply to the premises. |
2368 Here is a tactic doing exactly that: |
2422 Here is a tactic doing exactly that: |
2369 *} |
2423 *} |
2370 |
2424 |
2371 ML{*fun true1_tac ctxt = |
2425 ML{*fun true1_tac ctxt = |
2372 CONVERSION |
2426 CONVERSION |
2373 (Conv.params_conv ~1 (fn ctxt => |
2427 (Conv.params_conv ~1 (fn ctxt => |
2374 (Conv.prems_conv ~1 (if_true1_conv ctxt) then_conv |
2428 (Conv.prems_conv ~1 (if_true1_conv ctxt) then_conv |
2375 Conv.concl_conv ~1 (all_true1_conv ctxt))) ctxt)*} |
2429 Conv.concl_conv ~1 (true_conj1_conv ctxt))) ctxt)*} |
2376 |
2430 |
2377 text {* |
2431 text {* |
2378 We call the conversions with the argument @{ML "~1"}. This is to |
2432 We call the conversions with the argument @{ML "~1"}. This is to |
2379 analyse all parameters, premises and conclusions. If we call them with |
2433 analyse all parameters, premises and conclusions. If we call them with |
2380 a non-negative number, say @{text n}, then these conversions will |
2434 a non-negative number, say @{text n}, then these conversions will |