2073 *} |
2073 *} |
2074 |
2074 |
2075 section {* Conversions\label{sec:conversion} *} |
2075 section {* Conversions\label{sec:conversion} *} |
2076 |
2076 |
2077 text {* |
2077 text {* |
2078 Conversions are a thin layer on top of Isabelle's inference kernel, and |
2078 Conversions are a thin layer on top of Isabelle's inference kernel, and can |
2079 can be viewed as a controllable, bare-bone version of Isabelle's simplifier. |
2079 be viewed as a controllable, bare-bone version of Isabelle's simplifier. |
2080 One difference between a conversion and the simplifier is that the former |
2080 The purpose of conversions is to manipulate on @{ML_type cterm}s. However, |
2081 acts on @{ML_type cterm}s while the latter acts on @{ML_type thm}s. |
2081 we will also show in this section how conversions can be applied to theorems |
2082 However, we will also show in this section how conversions can be applied |
2082 and used as tactics. The type of conversions is |
2083 to theorems and used as tactics. The type for conversions is |
|
2084 *} |
2083 *} |
2085 |
2084 |
2086 ML{*type conv = cterm -> thm*} |
2085 ML{*type conv = cterm -> thm*} |
2087 |
2086 |
2088 text {* |
2087 text {* |
2199 in |
2198 in |
2200 (conv ctrm1, conv ctrm2) |
2199 (conv ctrm1, conv ctrm2) |
2201 end" |
2200 end" |
2202 "(True \<and> Q \<equiv> Q, P \<or> True \<and> Q \<equiv> P \<or> True \<and> Q)"} |
2201 "(True \<and> Q \<equiv> Q, P \<or> True \<and> Q \<equiv> P \<or> True \<and> Q)"} |
2203 |
2202 |
2204 Here the conversion of @{thm [source] true_conj1} only applies |
2203 Here the conversion @{thm [source] true_conj1} only applies |
2205 in the first case, but fails in the second. The whole conversion |
2204 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 |
2205 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. The same |
2206 try out @{ML all_conv in Conv}, which always succeeds. The same |
2208 behaviour can also be achieved with conversion combinator @{ML_ind try_conv in Conv}. |
2207 behaviour can also be achieved with conversion combinator @{ML_ind try_conv in Conv}. |
2209 For example |
2208 For example |
2279 | _ $ _ => Conv.comb_conv (true_conj1_conv ctxt) ctrm |
2278 | _ $ _ => Conv.comb_conv (true_conj1_conv ctxt) ctrm |
2280 | Abs _ => Conv.abs_conv (fn (_, ctxt) => true_conj1_conv ctxt) ctxt ctrm |
2279 | Abs _ => Conv.abs_conv (fn (_, ctxt) => true_conj1_conv ctxt) ctxt ctrm |
2281 | _ => Conv.all_conv ctrm*} |
2280 | _ => Conv.all_conv ctrm*} |
2282 |
2281 |
2283 text {* |
2282 text {* |
2284 This function ``fires'' if the terms is of the form @{text "(True \<and> \<dots>)"}. |
2283 This function ``fires'' if the term is of the form @{text "(True \<and> \<dots>)"}. |
2285 It descends under applications (Line 6 and 7) and abstractions |
2284 It descends under applications (Line 6) and abstractions |
2286 (Line 8); otherwise it leaves the term unchanged (Line 9). In Line 2 |
2285 (Line 7); otherwise it leaves the term unchanged (Line 8). In Line 2 |
2287 we need to transform the @{ML_type cterm} into a @{ML_type term} in order |
2286 we need to transform the @{ML_type cterm} into a @{ML_type term} in order |
2288 to be able to pattern-match the term. To see this |
2287 to be able to pattern-match the term. To see this |
2289 conversion in action, consider the following example: |
2288 conversion in action, consider the following example: |
2290 |
2289 |
2291 @{ML_response_fake [display,gray] |
2290 @{ML_response_fake [display,gray] |
2359 text {* |
2358 text {* |
2360 In the first function we only treat the top-most redex and also only the |
2359 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 |
2360 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 |
2361 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 |
2362 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 |
2363 root and applies it to all the redexes on the way, but stops in each branch as |
2365 soon as it found one redex.\footnote{\bf Fixme: Check with Sascha whether |
2364 soon as it found one redex. Here is an example for this conversion: |
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 |
2365 |
2369 |
2366 |
2370 @{ML_response_fake [display,gray] |
2367 @{ML_response_fake [display,gray] |
2371 "let |
2368 "let |
2372 val ctrm = @{cterm \"if P (True \<and> 1 \<noteq> (2::nat)) |
2369 val ctrm = @{cterm \"if P (True \<and> 1 \<noteq> (2::nat)) |
2427 (Conv.params_conv ~1 (fn ctxt => |
2424 (Conv.params_conv ~1 (fn ctxt => |
2428 (Conv.prems_conv ~1 (if_true1_conv ctxt) then_conv |
2425 (Conv.prems_conv ~1 (if_true1_conv ctxt) then_conv |
2429 Conv.concl_conv ~1 (true_conj1_conv ctxt))) ctxt)*} |
2426 Conv.concl_conv ~1 (true_conj1_conv ctxt))) ctxt)*} |
2430 |
2427 |
2431 text {* |
2428 text {* |
2432 We call the conversions with the argument @{ML "~1"}. This is to |
2429 We call the conversions with the argument @{ML "~1"}. By this we |
2433 analyse all parameters, premises and conclusions. If we call them with |
2430 analyse all parameters, all premises and the conclusion of a goal |
2434 a non-negative number, say @{text n}, then these conversions will |
2431 state. If we call @{ML concl_conv in Conv} with |
2435 only be called on @{text n} premises (similar for parameters and |
2432 a non-negative number, say @{text n}, then this conversions will |
2436 conclusions). To test the tactic, consider the proof |
2433 skip the first @{text n} premises and applies the conversion to the |
|
2434 ``rest'' (similar for parameters and conclusions). To test the |
|
2435 tactic, consider the proof |
2437 *} |
2436 *} |
2438 |
2437 |
2439 lemma |
2438 lemma |
2440 "if True \<and> P then P else True \<and> False \<Longrightarrow> |
2439 "if True \<and> P then P else True \<and> False \<Longrightarrow> |
2441 (if True \<and> Q then True \<and> Q else P) \<longrightarrow> True \<and> (True \<and> Q)" |
2440 (if True \<and> Q then True \<and> Q else P) \<longrightarrow> True \<and> (True \<and> Q)" |
2471 |
2470 |
2472 @{ML_response_fake [display,gray] |
2471 @{ML_response_fake [display,gray] |
2473 "Drule.abs_def @{thm id1_def}" |
2472 "Drule.abs_def @{thm id1_def}" |
2474 "id1 \<equiv> \<lambda>x. x"} |
2473 "id1 \<equiv> \<lambda>x. x"} |
2475 |
2474 |
2476 Unfortunately, Isabelle has no build-in function that transforms the |
2475 Unfortunately, Isabelle has no built-in function that transforms the |
2477 theorems in the other direction. We can conveniently implement one using |
2476 theorems in the other direction. We can implement one using |
2478 conversions. The feature of conversions we are using is that if we apply a |
2477 conversions. The feature of conversions we are using is that if we apply a |
2479 @{ML_type cterm} to a conversion we obtain a meta-equality theorem (recall |
2478 @{ML_type cterm} to a conversion we obtain a meta-equality theorem (recall |
2480 that the type of conversions is an abbreviation for |
2479 that the type of conversions is an abbreviation for |
2481 @{ML_type "cterm -> thm"}). The code of the transformation is below. |
2480 @{ML_type "cterm -> thm"}). The code of the transformation is below. |
2482 *} |
2481 *} |
2503 corresponding to the left-hand and right-hand side of the meta-equality. The |
2502 corresponding to the left-hand and right-hand side of the meta-equality. The |
2504 assumption in @{ML unabs_def} is that the right-hand side is an |
2503 assumption in @{ML unabs_def} is that the right-hand side is an |
2505 abstraction. We compute the possibly empty list of abstracted variables in |
2504 abstraction. We compute the possibly empty list of abstracted variables in |
2506 Line 4 using the function @{ML_ind strip_abs_vars in Term}. For this we have to |
2505 Line 4 using the function @{ML_ind strip_abs_vars in Term}. For this we have to |
2507 transform the @{ML_type cterm} into a @{ML_type term}. In Line 5 we |
2506 transform the @{ML_type cterm} into a @{ML_type term}. In Line 5 we |
2508 importing these variables into the context @{ML_text ctxt'}, in order to |
2507 import these variables into the context @{text "ctxt'"}, in order to |
2509 export them again in Line 15. In Line 8 we certify the list of variables, |
2508 export them again in Line 15. In Line 8 we certify the list of variables, |
2510 which in turn we apply to the @{ML_text lhs} of the definition using the |
2509 which in turn we apply to the @{ML_text lhs} of the definition using the |
2511 function @{ML_ind list_comb in Drule}. In Line 11 and 12 we generate the |
2510 function @{ML_ind list_comb in Drule}. In Line 11 and 12 we generate the |
2512 conversion according to the length of the list of (abstracted) variables. If |
2511 conversion according to the length of the list of (abstracted) variables. If |
2513 there are none, then we just return the conversion corresponding to the |
2512 there are none, then we just return the conversion corresponding to the |
2514 original definition. If there are variables, then we have to prefix this |
2513 original definition. If there are variables, then we have to prefix this |
2515 conversion with @{ML_ind fun_conv in Conv}. Now in Line 14 we only have to |
2514 conversion with @{ML_ind fun_conv in Conv}. Now in Line 14 we only have to |
2516 apply the new left-hand side to the generated conversion and obtain the the |
2515 apply the new left-hand side to the generated conversion and obtain the the |
2517 theorem we want to construct. As mentioned above, in Line 15 we only have to |
2516 theorem we want to construct. As mentioned above, in Line 15 we only have to |
2518 export the context @{ML_text ctxt'} in order to produce meta-variables for |
2517 export the context @{text "ctxt'"} back to @{text "ctxt"} in order to |
2519 the theorem. An example is as follows. |
2518 produce meta-variables for the theorem. An example is as follows. |
2520 |
2519 |
2521 @{ML_response_fake [display, gray] |
2520 @{ML_response_fake [display, gray] |
2522 "unabs_def @{context} @{thm id2_def}" |
2521 "unabs_def @{context} @{thm id2_def}" |
2523 "id2 ?x1 \<equiv> ?x1"} |
2522 "id2 ?x1 \<equiv> ?x1"} |
2524 *} |
2523 *} |
2525 |
2524 |
2526 text {* |
2525 text {* |
2527 To sum up this section, conversions are more general than the simplifier |
2526 To sum up this section, conversions are more general than the simplifier |
2528 or simprocs, but you have to do more work yourself. Also conversions are |
2527 or simprocs, but you have to do more work yourself. Also conversions are |
2529 often much less efficient than the simplifier. The advantage of conversions, |
2528 often much less efficient than the simplifier. The advantage of conversions, |
2530 however, that they provide much less room for non-termination. |
2529 however, is that they provide much less room for non-termination. |
2531 |
2530 |
2532 \begin{exercise}\label{ex:addconversion} |
2531 \begin{exercise}\label{ex:addconversion} |
2533 Write a tactic that does the same as the simproc in exercise |
2532 Write a tactic that does the same as the simproc in exercise |
2534 \ref{ex:addsimproc}, but is based on conversions. You can make |
2533 \ref{ex:addsimproc}, but is based on conversions. You can make |
2535 the same assumptions as in \ref{ex:addsimproc}. |
2534 the same assumptions as in \ref{ex:addsimproc}. |