ProgTutorial/Tactical.thy
changeset 406 f399b6855546
parent 405 f8d020bbc2c0
child 408 ef048892d0f0
equal deleted inserted replaced
405:f8d020bbc2c0 406:f399b6855546
  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]
  2312 end*}
  2311 end*}
  2313 
  2312 
  2314 text {*
  2313 text {*
  2315   The function @{ML bottom_conv in More_Conv} traverses first the the term and
  2314   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
  2315   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, 
  2316   More_Conv} applies the conversion on the ``way up''. To see the difference, 
  2318   assume the following two meta-equations.
  2317   assume the following two meta-equations.
  2319 *}
  2318 *}
  2320 
  2319 
  2321 lemma conj_assoc:
  2320 lemma conj_assoc:
  2322   fixes A B C::bool
  2321   fixes A B C::bool
  2325 by simp_all
  2324 by simp_all
  2326 
  2325 
  2327 text {*
  2326 text {*
  2328   and the @{ML_type cterm} @{text "(a \<and> (b \<and> c)) \<and> d"}. The reader should
  2327   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 
  2328   pause for a moment to be convinced that rewriting top-down and bottom-up 
  2330   according to the lemma produces two results. 
  2329   according to the two meta-equations produces two results. 
  2331 
  2330 
  2332   @{ML_response_fake [display, gray]
  2331   @{ML_response_fake [display, gray]
  2333   "let
  2332   "let
  2334   val ctxt = @{context}
  2333   val ctxt = @{context}
  2335   val conv = Conv.try_conv (More_Conv.rewrs_conv @{thms conj_assoc})
  2334   val conv = Conv.try_conv (More_Conv.rewrs_conv @{thms conj_assoc})
  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}.