201 apply(drule spec[where x=P]) |
199 apply(drule spec[where x=P]) |
202 apply(drule spec[where x=Q]) |
200 apply(drule spec[where x=Q]) |
203 apply(assumption) |
201 apply(assumption) |
204 done |
202 done |
205 |
203 |
206 text {* |
204 text \<open> |
207 The code for automating such induction principles has to accomplish two tasks: |
205 The code for automating such induction principles has to accomplish two tasks: |
208 constructing the induction principles from the given introduction |
206 constructing the induction principles from the given introduction |
209 rules and then automatically generating proofs for them using a tactic. |
207 rules and then automatically generating proofs for them using a tactic. |
210 |
208 |
211 The tactic will use the following helper function for instantiating universal |
209 The tactic will use the following helper function for instantiating universal |
212 quantifiers. |
210 quantifiers. |
213 *} |
211 \<close> |
214 |
212 |
215 ML %grayML{*fun inst_spec ctrm = |
213 ML %grayML\<open>fun inst_spec ctrm = |
216 let |
214 let |
217 val cty = Thm.ctyp_of_cterm ctrm |
215 val cty = Thm.ctyp_of_cterm ctrm |
218 in |
216 in |
219 Thm.instantiate' [SOME cty] [NONE, SOME ctrm] @{thm spec} |
217 Thm.instantiate' [SOME cty] [NONE, SOME ctrm] @{thm spec} |
220 end*} |
218 end\<close> |
221 |
219 |
222 text {* |
220 text \<open> |
223 This helper function uses the function @{ML_ind instantiate' in Thm} |
221 This helper function uses the function @{ML_ind instantiate' in Thm} |
224 and instantiates the @{text "?x"} in the theorem @{thm spec} with a given |
222 and instantiates the \<open>?x\<close> in the theorem @{thm spec} with a given |
225 @{ML_type cterm}. We call this helper function in the following |
223 @{ML_type cterm}. We call this helper function in the following |
226 tactic.\label{fun:instspectac}. |
224 tactic.\label{fun:instspectac}. |
227 *} |
225 \<close> |
228 |
226 |
229 ML %grayML{*fun inst_spec_tac ctxt ctrms = |
227 ML %grayML\<open>fun inst_spec_tac ctxt ctrms = |
230 EVERY' (map (dresolve_tac ctxt o single o inst_spec) ctrms)*} |
228 EVERY' (map (dresolve_tac ctxt o single o inst_spec) ctrms)\<close> |
231 |
229 |
232 text {* |
230 text \<open> |
233 This tactic expects a list of @{ML_type cterm}s. It allows us in the |
231 This tactic expects a list of @{ML_type cterm}s. It allows us in the |
234 proof below to instantiate the three quantifiers in the assumption. |
232 proof below to instantiate the three quantifiers in the assumption. |
235 *} |
233 \<close> |
236 |
234 |
237 lemma |
235 lemma |
238 fixes P::"nat \<Rightarrow> nat \<Rightarrow> nat \<Rightarrow> bool" |
236 fixes P::"nat \<Rightarrow> nat \<Rightarrow> nat \<Rightarrow> bool" |
239 shows "\<forall>x y z. P x y z \<Longrightarrow> True" |
237 shows "\<forall>x y z. P x y z \<Longrightarrow> True" |
240 apply (tactic {* |
238 apply (tactic \<open> |
241 inst_spec_tac @{context} [@{cterm "a::nat"},@{cterm "b::nat"},@{cterm "c::nat"}] 1 *}) |
239 inst_spec_tac @{context} [@{cterm "a::nat"},@{cterm "b::nat"},@{cterm "c::nat"}] 1\<close>) |
242 txt {* |
240 txt \<open> |
243 We obtain the goal state |
241 We obtain the goal state |
244 |
242 |
245 \begin{minipage}{\textwidth} |
243 \begin{minipage}{\textwidth} |
246 @{subgoals} |
244 @{subgoals} |
247 \end{minipage}*} |
245 \end{minipage}\<close> |
248 (*<*)oops(*>*) |
246 (*<*)oops(*>*) |
249 |
247 |
250 text {* |
248 text \<open> |
251 The complete tactic for proving the induction principles can now |
249 The complete tactic for proving the induction principles can now |
252 be implemented as follows: |
250 be implemented as follows: |
253 *} |
251 \<close> |
254 |
252 |
255 ML %linenosgray{*fun ind_tac ctxt defs prem insts = |
253 ML %linenosgray\<open>fun ind_tac ctxt defs prem insts = |
256 EVERY1 [Object_Logic.full_atomize_tac ctxt, |
254 EVERY1 [Object_Logic.full_atomize_tac ctxt, |
257 cut_facts_tac prem, |
255 cut_facts_tac prem, |
258 rewrite_goal_tac ctxt defs, |
256 rewrite_goal_tac ctxt defs, |
259 inst_spec_tac ctxt insts, |
257 inst_spec_tac ctxt insts, |
260 assume_tac ctxt]*} |
258 assume_tac ctxt]\<close> |
261 |
259 |
262 text {* |
260 text \<open> |
263 We have to give it as arguments the definitions, the premise (a list of |
261 We have to give it as arguments the definitions, the premise (a list of |
264 formulae) and the instantiations. The premise is @{text "even n"} in lemma |
262 formulae) and the instantiations. The premise is \<open>even n\<close> in lemma |
265 @{thm [source] manual_ind_prin_even} shown above; in our code it will always be a list |
263 @{thm [source] manual_ind_prin_even} shown above; in our code it will always be a list |
266 consisting of a single formula. Compare this tactic with the manual proof |
264 consisting of a single formula. Compare this tactic with the manual proof |
267 for the lemma @{thm [source] manual_ind_prin_even}: as you can see there is |
265 for the lemma @{thm [source] manual_ind_prin_even}: as you can see there is |
268 almost a one-to-one correspondence between the \isacommand{apply}-script and |
266 almost a one-to-one correspondence between the \isacommand{apply}-script and |
269 the @{ML ind_tac}. We first rewrite the goal to use only object connectives (Line 2), |
267 the @{ML ind_tac}. We first rewrite the goal to use only object connectives (Line 2), |
270 "cut in" the premise (Line 3), unfold the definitions (Line 4), instantiate |
268 "cut in" the premise (Line 3), unfold the definitions (Line 4), instantiate |
271 the assumptions of the goal (Line 5) and then conclude with @{ML assume_tac}. |
269 the assumptions of the goal (Line 5) and then conclude with @{ML assume_tac}. |
272 |
270 |
273 Two testcases for this tactic are: |
271 Two testcases for this tactic are: |
274 *} |
272 \<close> |
275 |
273 |
276 lemma automatic_ind_prin_even: |
274 lemma automatic_ind_prin_even: |
277 assumes prem: "even z" |
275 assumes prem: "even z" |
278 shows "P 0 \<Longrightarrow> (\<And>m. Q m \<Longrightarrow> P (Suc m)) \<Longrightarrow> (\<And>m. P m \<Longrightarrow> Q (Suc m)) \<Longrightarrow> P z" |
276 shows "P 0 \<Longrightarrow> (\<And>m. Q m \<Longrightarrow> P (Suc m)) \<Longrightarrow> (\<And>m. P m \<Longrightarrow> Q (Suc m)) \<Longrightarrow> P z" |
279 by (tactic {* ind_tac @{context} eo_defs @{thms prem} |
277 by (tactic \<open>ind_tac @{context} eo_defs @{thms prem} |
280 [@{cterm "P::nat\<Rightarrow>bool"}, @{cterm "Q::nat\<Rightarrow>bool"}] *}) |
278 [@{cterm "P::nat\<Rightarrow>bool"}, @{cterm "Q::nat\<Rightarrow>bool"}]\<close>) |
281 |
279 |
282 lemma automatic_ind_prin_fresh: |
280 lemma automatic_ind_prin_fresh: |
283 assumes prem: "fresh z za" |
281 assumes prem: "fresh z za" |
284 shows "(\<And>a b. a \<noteq> b \<Longrightarrow> P a (Var b)) \<Longrightarrow> |
282 shows "(\<And>a b. a \<noteq> b \<Longrightarrow> P a (Var b)) \<Longrightarrow> |
285 (\<And>a t s. \<lbrakk>P a t; P a s\<rbrakk> \<Longrightarrow> P a (App t s)) \<Longrightarrow> |
283 (\<And>a t s. \<lbrakk>P a t; P a s\<rbrakk> \<Longrightarrow> P a (App t s)) \<Longrightarrow> |
286 (\<And>a t. P a (Lam a t)) \<Longrightarrow> |
284 (\<And>a t. P a (Lam a t)) \<Longrightarrow> |
287 (\<And>a b t. \<lbrakk>a \<noteq> b; P a t\<rbrakk> \<Longrightarrow> P a (Lam b t)) \<Longrightarrow> P z za" |
285 (\<And>a b t. \<lbrakk>a \<noteq> b; P a t\<rbrakk> \<Longrightarrow> P a (Lam b t)) \<Longrightarrow> P z za" |
288 by (tactic {* ind_tac @{context} @{thms fresh_def} @{thms prem} |
286 by (tactic \<open>ind_tac @{context} @{thms fresh_def} @{thms prem} |
289 [@{cterm "P::string\<Rightarrow>trm\<Rightarrow>bool"}] *}) |
287 [@{cterm "P::string\<Rightarrow>trm\<Rightarrow>bool"}]\<close>) |
290 |
288 |
291 |
289 |
292 text {* |
290 text \<open> |
293 While the tactic for proving the induction principles is relatively simple, |
291 While the tactic for proving the induction principles is relatively simple, |
294 it will be a bit more work to construct the goals from the introduction rules |
292 it will be a bit more work to construct the goals from the introduction rules |
295 the user provides. Therefore let us have a closer look at the first |
293 the user provides. Therefore let us have a closer look at the first |
296 proved theorem: |
294 proved theorem: |
297 |
295 |
298 \begin{isabelle} |
296 \begin{isabelle} |
299 \isacommand{thm}~@{thm [source] automatic_ind_prin_even}\\ |
297 \isacommand{thm}~@{thm [source] automatic_ind_prin_even}\\ |
300 @{text "> "}~@{thm automatic_ind_prin_even} |
298 \<open>> \<close>~@{thm automatic_ind_prin_even} |
301 \end{isabelle} |
299 \end{isabelle} |
302 |
300 |
303 The variables @{text "z"}, @{text "P"} and @{text "Q"} are schematic |
301 The variables \<open>z\<close>, \<open>P\<close> and \<open>Q\<close> are schematic |
304 variables (since they are not quantified in the lemma). These |
302 variables (since they are not quantified in the lemma). These |
305 variables must be schematic, otherwise they cannot be instantiated |
303 variables must be schematic, otherwise they cannot be instantiated |
306 by the user. To generate these schematic variables we use a common trick |
304 by the user. To generate these schematic variables we use a common trick |
307 in Isabelle programming: we first declare them as \emph{free}, |
305 in Isabelle programming: we first declare them as \emph{free}, |
308 \emph{but fixed}, and then use the infrastructure to turn them into |
306 \emph{but fixed}, and then use the infrastructure to turn them into |
309 schematic variables. |
307 schematic variables. |
310 |
308 |
311 In general we have to construct for each predicate @{text "pred"} a goal |
309 In general we have to construct for each predicate \<open>pred\<close> a goal |
312 of the form |
310 of the form |
313 |
311 |
314 @{text [display] |
312 @{text [display] |
315 "pred ?zs \<Longrightarrow> rules[preds := ?Ps] \<Longrightarrow> ?P ?zs"} |
313 "pred ?zs \<Longrightarrow> rules[preds := ?Ps] \<Longrightarrow> ?P ?zs"} |
316 |
314 |
317 where the predicates @{text preds} are replaced in @{text rules} by new |
315 where the predicates \<open>preds\<close> are replaced in \<open>rules\<close> by new |
318 distinct variables @{text "?Ps"}. We also need to generate fresh arguments |
316 distinct variables \<open>?Ps\<close>. We also need to generate fresh arguments |
319 @{text "?zs"} for the predicate @{text "pred"} and the @{text "?P"} in |
317 \<open>?zs\<close> for the predicate \<open>pred\<close> and the \<open>?P\<close> in |
320 the conclusion. |
318 the conclusion. |
321 |
319 |
322 We generate these goals in two steps. The first function, named @{text prove_ind}, |
320 We generate these goals in two steps. The first function, named \<open>prove_ind\<close>, |
323 expects that the introduction rules are already appropriately substituted. The argument |
321 expects that the introduction rules are already appropriately substituted. The argument |
324 @{text "srules"} stands for these substituted rules; @{text cnewpreds} are |
322 \<open>srules\<close> stands for these substituted rules; \<open>cnewpreds\<close> are |
325 the certified terms coresponding to the variables @{text "?Ps"}; @{text |
323 the certified terms coresponding to the variables \<open>?Ps\<close>; \<open>pred\<close> is the predicate for which we prove the induction principle; |
326 "pred"} is the predicate for which we prove the induction principle; |
324 \<open>newpred\<close> is its replacement and \<open>arg_tys\<close> are the argument |
327 @{text "newpred"} is its replacement and @{text "arg_tys"} are the argument |
|
328 types of this predicate. |
325 types of this predicate. |
329 *} |
326 \<close> |
330 |
327 |
331 ML %linenosgray{*fun prove_ind lthy defs srules cnewpreds ((pred, newpred), arg_tys) = |
328 ML %linenosgray\<open>fun prove_ind lthy defs srules cnewpreds ((pred, newpred), arg_tys) = |
332 let |
329 let |
333 val zs = replicate (length arg_tys) "z" |
330 val zs = replicate (length arg_tys) "z" |
334 val (newargnames, lthy') = Variable.variant_fixes zs lthy; |
331 val (newargnames, lthy') = Variable.variant_fixes zs lthy; |
335 val newargs = map Free (newargnames ~~ arg_tys) |
332 val newargs = map Free (newargnames ~~ arg_tys) |
336 |
333 |
520 pwriteln (pretty_thm_no_vars @{context} res) |
517 pwriteln (pretty_thm_no_vars @{context} res) |
521 end" |
518 end" |
522 "C"} |
519 "C"} |
523 |
520 |
524 Now we set up the proof for the introduction rule as follows: |
521 Now we set up the proof for the introduction rule as follows: |
525 *} |
522 \<close> |
526 |
523 |
527 lemma fresh_Lam: |
524 lemma fresh_Lam: |
528 shows "\<And>a b t. \<lbrakk>a \<noteq> b; fresh a t\<rbrakk> \<Longrightarrow> fresh a (Lam b t)" |
525 shows "\<And>a b t. \<lbrakk>a \<noteq> b; fresh a t\<rbrakk> \<Longrightarrow> fresh a (Lam b t)" |
529 (*<*)oops(*>*) |
526 (*<*)oops(*>*) |
530 |
527 |
531 text {* |
528 text \<open> |
532 The first step in the proof will be to expand the definitions of freshness |
529 The first step in the proof will be to expand the definitions of freshness |
533 and then introduce quantifiers and implications. For this we |
530 and then introduce quantifiers and implications. For this we |
534 will use the tactic |
531 will use the tactic |
535 *} |
532 \<close> |
536 |
533 |
537 ML %linenosgray{*fun expand_tac ctxt defs = |
534 ML %linenosgray\<open>fun expand_tac ctxt defs = |
538 Object_Logic.rulify_tac ctxt 1 |
535 Object_Logic.rulify_tac ctxt 1 |
539 THEN rewrite_goal_tac ctxt defs 1 |
536 THEN rewrite_goal_tac ctxt defs 1 |
540 THEN (REPEAT (resolve_tac ctxt [@{thm allI}, @{thm impI}] 1)) *} |
537 THEN (REPEAT (resolve_tac ctxt [@{thm allI}, @{thm impI}] 1))\<close> |
541 |
538 |
542 text {* |
539 text \<open> |
543 The function in Line 2 ``rulifies'' the lemma.\footnote{FIXME: explain this better} |
540 The function in Line 2 ``rulifies'' the lemma.\footnote{FIXME: explain this better} |
544 This will turn out to |
541 This will turn out to |
545 be important later on. Applying this tactic in our proof of @{text "fresh_Lem"} |
542 be important later on. Applying this tactic in our proof of \<open>fresh_Lem\<close> |
546 *} |
543 \<close> |
547 |
544 |
548 (*<*) |
545 (*<*) |
549 lemma fresh_Lam: |
546 lemma fresh_Lam: |
550 shows "\<And>a b t. \<lbrakk>a \<noteq> b; fresh a t\<rbrakk> \<Longrightarrow> fresh a (Lam b t)" |
547 shows "\<And>a b t. \<lbrakk>a \<noteq> b; fresh a t\<rbrakk> \<Longrightarrow> fresh a (Lam b t)" |
551 (*>*) |
548 (*>*) |
552 apply(tactic {* expand_tac @{context} @{thms fresh_def} *}) |
549 apply(tactic \<open>expand_tac @{context} @{thms fresh_def}\<close>) |
553 |
550 |
554 txt {* |
551 txt \<open> |
555 gives us the goal state |
552 gives us the goal state |
556 |
553 |
557 \begin{isabelle} |
554 \begin{isabelle} |
558 @{subgoals [display]} |
555 @{subgoals [display]} |
559 \end{isabelle} |
556 \end{isabelle} |
560 |
557 |
561 As you can see, there are parameters (namely @{text "a"}, @{text "b"} and |
558 As you can see, there are parameters (namely \<open>a\<close>, \<open>b\<close> and |
562 @{text "t"}) which come from the introduction rule and parameters (in the |
559 \<open>t\<close>) which come from the introduction rule and parameters (in the |
563 case above only @{text "fresh"}) which come from the universal |
560 case above only \<open>fresh\<close>) which come from the universal |
564 quantification in the definition @{term "fresh a (App t s)"}. Similarly, |
561 quantification in the definition @{term "fresh a (App t s)"}. Similarly, |
565 there are assumptions that come from the premises of the rule (namely the |
562 there are assumptions that come from the premises of the rule (namely the |
566 first two) and assumptions from the definition of the predicate (assumption |
563 first two) and assumptions from the definition of the predicate (assumption |
567 three to six). We need to treat these parameters and assumptions |
564 three to six). We need to treat these parameters and assumptions |
568 differently. In the code below we will therefore separate them into @{text |
565 differently. In the code below we will therefore separate them into \<open>params1\<close> and \<open>params2\<close>, respectively \<open>prems1\<close> and \<open>prems2\<close>. To do this separation, it is best to open a subproof with the |
569 "params1"} and @{text params2}, respectively @{text "prems1"} and @{text |
|
570 "prems2"}. To do this separation, it is best to open a subproof with the |
|
571 tactic @{ML_ind SUBPROOF in Subgoal}, since this tactic provides us with the parameters (as |
566 tactic @{ML_ind SUBPROOF in Subgoal}, since this tactic provides us with the parameters (as |
572 list of @{ML_type cterm}s) and the assumptions (as list of @{ML_type thm}s). |
567 list of @{ML_type cterm}s) and the assumptions (as list of @{ML_type thm}s). |
573 The problem with @{ML SUBPROOF}, however, is that it always expects us to |
568 The problem with @{ML SUBPROOF}, however, is that it always expects us to |
574 completely discharge the goal (see Section~\ref{sec:simpletacs}). This is |
569 completely discharge the goal (see Section~\ref{sec:simpletacs}). This is |
575 a bit inconvenient for our gradual explanation of the proof here. Therefore |
570 a bit inconvenient for our gradual explanation of the proof here. Therefore |
576 we use first the function @{ML_ind FOCUS in Subgoal}, which does s |
571 we use first the function @{ML_ind FOCUS in Subgoal}, which does s |
577 ame as @{ML SUBPROOF} |
572 ame as @{ML SUBPROOF} |
578 but does not require us to completely discharge the goal. |
573 but does not require us to completely discharge the goal. |
579 *} |
574 \<close> |
580 (*<*)oops(*>*) |
575 (*<*)oops(*>*) |
581 text_raw {* |
576 text_raw \<open> |
582 \begin{figure}[t] |
577 \begin{figure}[t] |
583 \begin{minipage}{\textwidth} |
578 \begin{minipage}{\textwidth} |
584 \begin{isabelle} |
579 \begin{isabelle} |
585 *} |
580 \<close> |
586 ML %grayML{*fun chop_print params1 params2 prems1 prems2 ctxt = |
581 ML %grayML\<open>fun chop_print params1 params2 prems1 prems2 ctxt = |
587 let |
582 let |
588 val pps = [Pretty.big_list "Params1 from the rule:" (map (pretty_cterm ctxt) params1), |
583 val pps = [Pretty.big_list "Params1 from the rule:" (map (pretty_cterm ctxt) params1), |
589 Pretty.big_list "Params2 from the predicate:" (map (pretty_cterm ctxt) params2), |
584 Pretty.big_list "Params2 from the predicate:" (map (pretty_cterm ctxt) params2), |
590 Pretty.big_list "Prems1 from the rule:" (map (pretty_thm ctxt) prems1), |
585 Pretty.big_list "Prems1 from the rule:" (map (pretty_thm ctxt) prems1), |
591 Pretty.big_list "Prems2 from the predicate:" (map (pretty_thm ctxt) prems2)] |
586 Pretty.big_list "Prems2 from the predicate:" (map (pretty_thm ctxt) prems2)] |
592 in |
587 in |
593 pps |> Pretty.chunks |
588 pps |> Pretty.chunks |
594 |> Pretty.string_of |
589 |> Pretty.string_of |
595 |> tracing |
590 |> tracing |
596 end*} |
591 end\<close> |
597 |
592 |
598 text_raw{* |
593 text_raw\<open> |
599 \end{isabelle} |
594 \end{isabelle} |
600 \end{minipage} |
595 \end{minipage} |
601 \caption{A helper function that prints out the parameters and premises that |
596 \caption{A helper function that prints out the parameters and premises that |
602 need to be treated differently.\label{fig:chopprint}} |
597 need to be treated differently.\label{fig:chopprint}} |
603 \end{figure} |
598 \end{figure} |
604 *} |
599 \<close> |
605 |
600 |
606 text {* |
601 text \<open> |
607 First we calculate the values for @{text "params1/2"} and @{text "prems1/2"} |
602 First we calculate the values for \<open>params1/2\<close> and \<open>prems1/2\<close> |
608 from @{text "params"} and @{text "prems"}, respectively. To better see what is |
603 from \<open>params\<close> and \<open>prems\<close>, respectively. To better see what is |
609 going in our example, we will print out these values using the printing |
604 going in our example, we will print out these values using the printing |
610 function in Figure~\ref{fig:chopprint}. Since @{ML FOCUS in Subgoal} will |
605 function in Figure~\ref{fig:chopprint}. Since @{ML FOCUS in Subgoal} will |
611 supply us the @{text "params"} and @{text "prems"} as lists, we can |
606 supply us the \<open>params\<close> and \<open>prems\<close> as lists, we can |
612 separate them using the function @{ML_ind chop in Library}. |
607 separate them using the function @{ML_ind chop in Library}. |
613 *} |
608 \<close> |
614 |
609 |
615 ML %linenosgray{*fun chop_test_tac preds rules = |
610 ML %linenosgray\<open>fun chop_test_tac preds rules = |
616 Subgoal.FOCUS (fn {params, prems, context, ...} => |
611 Subgoal.FOCUS (fn {params, prems, context, ...} => |
617 let |
612 let |
618 val cparams = map snd params |
613 val cparams = map snd params |
619 val (params1, params2) = chop (length cparams - length preds) cparams |
614 val (params1, params2) = chop (length cparams - length preds) cparams |
620 val (prems1, prems2) = chop (length prems - length rules) prems |
615 val (prems1, prems2) = chop (length prems - length rules) prems |
621 in |
616 in |
622 chop_print params1 params2 prems1 prems2 context; all_tac |
617 chop_print params1 params2 prems1 prems2 context; all_tac |
623 end) *} |
618 end)\<close> |
624 |
619 |
625 text {* |
620 text \<open> |
626 For the separation we can rely on the fact that Isabelle deterministically |
621 For the separation we can rely on the fact that Isabelle deterministically |
627 produces parameters and premises in a goal state. The last parameters |
622 produces parameters and premises in a goal state. The last parameters |
628 that were introduced come from the quantifications in the definitions |
623 that were introduced come from the quantifications in the definitions |
629 (see the tactic @{ML expand_tac}). |
624 (see the tactic @{ML expand_tac}). |
630 Therefore we only have to subtract in Line 5 the number of predicates (in this |
625 Therefore we only have to subtract in Line 5 the number of predicates (in this |
631 case only @{text "1"}) from the lenghts of all parameters. Similarly |
626 case only \<open>1\<close>) from the lenghts of all parameters. Similarly |
632 with the @{text "prems"} in line 6: the last premises in the goal state come from |
627 with the \<open>prems\<close> in line 6: the last premises in the goal state come from |
633 unfolding the definition of the predicate in the conclusion. So we can |
628 unfolding the definition of the predicate in the conclusion. So we can |
634 just subtract the number of rules from the number of all premises. |
629 just subtract the number of rules from the number of all premises. |
635 To check our calculations we print them out in Line 8 using the |
630 To check our calculations we print them out in Line 8 using the |
636 function @{ML chop_print} from Figure~\ref{fig:chopprint} and then |
631 function @{ML chop_print} from Figure~\ref{fig:chopprint} and then |
637 just do nothing, that is @{ML all_tac}. Applying this tactic in our example |
632 just do nothing, that is @{ML all_tac}. Applying this tactic in our example |
638 *} |
633 \<close> |
639 |
634 |
640 (*<*) |
635 (*<*) |
641 lemma fresh_Lam: |
636 lemma fresh_Lam: |
642 shows "\<And>a b t. \<lbrakk>a \<noteq> b; fresh a t\<rbrakk> \<Longrightarrow> fresh a (Lam b t)" |
637 shows "\<And>a b t. \<lbrakk>a \<noteq> b; fresh a t\<rbrakk> \<Longrightarrow> fresh a (Lam b t)" |
643 apply(tactic {* expand_tac @{context} @{thms fresh_def} *}) |
638 apply(tactic \<open>expand_tac @{context} @{thms fresh_def}\<close>) |
644 (*>*) |
639 (*>*) |
645 apply(tactic {* chop_test_tac [fresh_pred] fresh_rules @{context} 1 *}) |
640 apply(tactic \<open>chop_test_tac [fresh_pred] fresh_rules @{context} 1\<close>) |
646 (*<*)oops(*>*) |
641 (*<*)oops(*>*) |
647 |
642 |
648 text {* |
643 text \<open> |
649 gives |
644 gives |
650 |
645 |
651 \begin{isabelle} |
646 \begin{isabelle} |
652 @{text "Params1 from the rule:"}\\ |
647 \<open>Params1 from the rule:\<close>\\ |
653 @{text "a, b, t"}\\ |
648 \<open>a, b, t\<close>\\ |
654 @{text "Params2 from the predicate:"}\\ |
649 \<open>Params2 from the predicate:\<close>\\ |
655 @{text "fresh"}\\ |
650 \<open>fresh\<close>\\ |
656 @{text "Prems1 from the rule:"}\\ |
651 \<open>Prems1 from the rule:\<close>\\ |
657 @{term "a \<noteq> b"}\\ |
652 @{term "a \<noteq> b"}\\ |
658 @{text [break] |
653 @{text [break] |
659 "\<forall>fresh. |
654 "\<forall>fresh. |
660 (\<forall>a b. a \<noteq> b \<longrightarrow> fresh a (Var b)) \<longrightarrow> |
655 (\<forall>a b. a \<noteq> b \<longrightarrow> fresh a (Var b)) \<longrightarrow> |
661 (\<forall>a t s. fresh a t \<longrightarrow> fresh a s \<longrightarrow> fresh a (App t s)) \<longrightarrow> |
656 (\<forall>a t s. fresh a t \<longrightarrow> fresh a s \<longrightarrow> fresh a (App t s)) \<longrightarrow> |
662 (\<forall>a t. fresh a (Lam a t)) \<longrightarrow> |
657 (\<forall>a t. fresh a (Lam a t)) \<longrightarrow> |
663 (\<forall>a b t. a \<noteq> b \<longrightarrow> fresh a t \<longrightarrow> fresh a (Lam b t)) \<longrightarrow> fresh a t"}\\ |
658 (\<forall>a b t. a \<noteq> b \<longrightarrow> fresh a t \<longrightarrow> fresh a (Lam b t)) \<longrightarrow> fresh a t"}\\ |
664 @{text "Prems2 from the predicate:"}\\ |
659 \<open>Prems2 from the predicate:\<close>\\ |
665 @{term "\<forall>a b. a \<noteq> b \<longrightarrow> fresh a (Var b)"}\\ |
660 @{term "\<forall>a b. a \<noteq> b \<longrightarrow> fresh a (Var b)"}\\ |
666 @{term "\<forall>a t s. fresh a t \<longrightarrow> fresh a s \<longrightarrow> fresh a (App t s)"}\\ |
661 @{term "\<forall>a t s. fresh a t \<longrightarrow> fresh a s \<longrightarrow> fresh a (App t s)"}\\ |
667 @{term "\<forall>a t. fresh a (Lam a t)"}\\ |
662 @{term "\<forall>a t. fresh a (Lam a t)"}\\ |
668 @{term "\<forall>a b t. a \<noteq> b \<longrightarrow> fresh a t \<longrightarrow> fresh a (Lam b t)"} |
663 @{term "\<forall>a b t. a \<noteq> b \<longrightarrow> fresh a t \<longrightarrow> fresh a (Lam b t)"} |
669 \end{isabelle} |
664 \end{isabelle} |
670 |
665 |
671 |
666 |
672 We now have to select from @{text prems2} the premise |
667 We now have to select from \<open>prems2\<close> the premise |
673 that corresponds to the introduction rule we prove, namely: |
668 that corresponds to the introduction rule we prove, namely: |
674 |
669 |
675 @{term [display] "\<forall>a b t. a \<noteq> b \<longrightarrow> fresh a t \<longrightarrow> fresh a (Lam a t)"} |
670 @{term [display] "\<forall>a b t. a \<noteq> b \<longrightarrow> fresh a t \<longrightarrow> fresh a (Lam a t)"} |
676 |
671 |
677 To use this premise with @{ML resolve_tac}, we need to instantiate its |
672 To use this premise with @{ML resolve_tac}, we need to instantiate its |
678 quantifiers (with @{text params1}) and transform it into rule |
673 quantifiers (with \<open>params1\<close>) and transform it into rule |
679 format (using @{ML_ind rulify in Object_Logic}). So we can modify the |
674 format (using @{ML_ind rulify in Object_Logic}). So we can modify the |
680 code as follows: |
675 code as follows: |
681 *} |
676 \<close> |
682 |
677 |
683 ML %linenosgray{*fun apply_prem_tac i preds rules = |
678 ML %linenosgray\<open>fun apply_prem_tac i preds rules = |
684 Subgoal.FOCUS (fn {params, prems, context, ...} => |
679 Subgoal.FOCUS (fn {params, prems, context, ...} => |
685 let |
680 let |
686 val cparams = map snd params |
681 val cparams = map snd params |
687 val (params1, params2) = chop (length cparams - length preds) cparams |
682 val (params1, params2) = chop (length cparams - length preds) cparams |
688 val (prems1, prems2) = chop (length prems - length rules) prems |
683 val (prems1, prems2) = chop (length prems - length rules) prems |
689 in |
684 in |
690 resolve_tac context [Object_Logic.rulify context (all_elims params1 (nth prems2 i))] 1 |
685 resolve_tac context [Object_Logic.rulify context (all_elims params1 (nth prems2 i))] 1 |
691 end) *} |
686 end)\<close> |
692 |
687 |
693 text {* |
688 text \<open> |
694 The argument @{text i} corresponds to the number of the |
689 The argument \<open>i\<close> corresponds to the number of the |
695 introduction we want to prove. We will later on let it range |
690 introduction we want to prove. We will later on let it range |
696 from @{text 0} to the number of @{text "rules - 1"}. |
691 from \<open>0\<close> to the number of \<open>rules - 1\<close>. |
697 Below we apply this function with @{text 3}, since |
692 Below we apply this function with \<open>3\<close>, since |
698 we are proving the fourth introduction rule. |
693 we are proving the fourth introduction rule. |
699 *} |
694 \<close> |
700 |
695 |
701 (*<*) |
696 (*<*) |
702 lemma fresh_Lam: |
697 lemma fresh_Lam: |
703 shows "\<And>a b t. \<lbrakk>a \<noteq> b; fresh a t\<rbrakk> \<Longrightarrow> fresh a (Lam b t)" |
698 shows "\<And>a b t. \<lbrakk>a \<noteq> b; fresh a t\<rbrakk> \<Longrightarrow> fresh a (Lam b t)" |
704 apply(tactic {* expand_tac @{context} @{thms fresh_def} *}) |
699 apply(tactic \<open>expand_tac @{context} @{thms fresh_def}\<close>) |
705 (*>*) |
700 (*>*) |
706 apply(tactic {* apply_prem_tac 3 [fresh_pred] fresh_rules @{context} 1 *}) |
701 apply(tactic \<open>apply_prem_tac 3 [fresh_pred] fresh_rules @{context} 1\<close>) |
707 (*<*)oops(*>*) |
702 (*<*)oops(*>*) |
708 |
703 |
709 text {* |
704 text \<open> |
710 The goal state we obtain is: |
705 The goal state we obtain is: |
711 |
706 |
712 \begin{isabelle} |
707 \begin{isabelle} |
713 @{text "1."}~@{text "\<dots> \<Longrightarrow> "}~@{prop "a \<noteq> b"}\\ |
708 \<open>1.\<close>~\<open>\<dots> \<Longrightarrow> \<close>~@{prop "a \<noteq> b"}\\ |
714 @{text "2."}~@{text "\<dots> \<Longrightarrow> "}~@{prop "fresh a t"} |
709 \<open>2.\<close>~\<open>\<dots> \<Longrightarrow> \<close>~@{prop "fresh a t"} |
715 \end{isabelle} |
710 \end{isabelle} |
716 |
711 |
717 As expected there are two subgoals, where the first comes from the |
712 As expected there are two subgoals, where the first comes from the |
718 non-recursive premise of the introduction rule and the second comes |
713 non-recursive premise of the introduction rule and the second comes |
719 from the recursive one. The first goal can be solved immediately |
714 from the recursive one. The first goal can be solved immediately |
720 by @{text "prems1"}. The second needs more work. It can be solved |
715 by \<open>prems1\<close>. The second needs more work. It can be solved |
721 with the other premise in @{text "prems1"}, namely |
716 with the other premise in \<open>prems1\<close>, namely |
722 |
717 |
723 |
718 |
724 @{term [break,display] |
719 @{term [break,display] |
725 "\<forall>fresh. |
720 "\<forall>fresh. |
726 (\<forall>a b. a \<noteq> b \<longrightarrow> fresh a (Var b)) \<longrightarrow> |
721 (\<forall>a b. a \<noteq> b \<longrightarrow> fresh a (Var b)) \<longrightarrow> |
727 (\<forall>a t s. fresh a t \<longrightarrow> fresh a s \<longrightarrow> fresh a (App t s)) \<longrightarrow> |
722 (\<forall>a t s. fresh a t \<longrightarrow> fresh a s \<longrightarrow> fresh a (App t s)) \<longrightarrow> |
728 (\<forall>a t. fresh a (Lam a t)) \<longrightarrow> |
723 (\<forall>a t. fresh a (Lam a t)) \<longrightarrow> |
729 (\<forall>a b t. a \<noteq> b \<longrightarrow> fresh a t \<longrightarrow> fresh a (Lam b t)) \<longrightarrow> fresh a t"} |
724 (\<forall>a b t. a \<noteq> b \<longrightarrow> fresh a t \<longrightarrow> fresh a (Lam b t)) \<longrightarrow> fresh a t"} |
730 |
725 |
731 but we have to instantiate it appropriately. These instantiations |
726 but we have to instantiate it appropriately. These instantiations |
732 come from @{text "params1"} and @{text "prems2"}. We can determine |
727 come from \<open>params1\<close> and \<open>prems2\<close>. We can determine |
733 whether we are in the simple or complicated case by checking whether |
728 whether we are in the simple or complicated case by checking whether |
734 the topmost connective is an @{text "\<forall>"}. The premises in the simple |
729 the topmost connective is an \<open>\<forall>\<close>. The premises in the simple |
735 case cannot have such a quantification, since the first step |
730 case cannot have such a quantification, since the first step |
736 of @{ML "expand_tac"} was to ``rulify'' the lemma. |
731 of @{ML "expand_tac"} was to ``rulify'' the lemma. |
737 The premise of the complicated case must have at least one @{text "\<forall>"} |
732 The premise of the complicated case must have at least one \<open>\<forall>\<close> |
738 coming from the quantification over the @{text preds}. So |
733 coming from the quantification over the \<open>preds\<close>. So |
739 we can implement the following function |
734 we can implement the following function |
740 *} |
735 \<close> |
741 |
736 |
742 ML %grayML{*fun prepare_prem ctxt params2 prems2 prem = |
737 ML %grayML\<open>fun prepare_prem ctxt params2 prems2 prem = |
743 resolve_tac ctxt [case Thm.prop_of prem of |
738 resolve_tac ctxt [case Thm.prop_of prem of |
744 _ $ (Const (@{const_name All}, _) $ _) => |
739 _ $ (Const (@{const_name All}, _) $ _) => |
745 prem |> all_elims params2 |
740 prem |> all_elims params2 |
746 |> imp_elims prems2 |
741 |> imp_elims prems2 |
747 | _ => prem] *} |
742 | _ => prem]\<close> |
748 |
743 |
749 text {* |
744 text \<open> |
750 which either applies the premise outright (the default case) or if |
745 which either applies the premise outright (the default case) or if |
751 it has an outermost universial quantification, instantiates it first |
746 it has an outermost universial quantification, instantiates it first |
752 with @{text "params1"} and then @{text "prems1"}. The following |
747 with \<open>params1\<close> and then \<open>prems1\<close>. The following |
753 tactic will therefore prove the lemma completely. |
748 tactic will therefore prove the lemma completely. |
754 *} |
749 \<close> |
755 |
750 |
756 ML %grayML{*fun prove_intro_tac i preds rules = |
751 ML %grayML\<open>fun prove_intro_tac i preds rules = |
757 SUBPROOF (fn {params, prems, context, ...} => |
752 SUBPROOF (fn {params, prems, context, ...} => |
758 let |
753 let |
759 val cparams = map snd params |
754 val cparams = map snd params |
760 val (params1, params2) = chop (length cparams - length preds) cparams |
755 val (params1, params2) = chop (length cparams - length preds) cparams |
761 val (prems1, prems2) = chop (length prems - length rules) prems |
756 val (prems1, prems2) = chop (length prems - length rules) prems |
762 in |
757 in |
763 resolve_tac context [Object_Logic.rulify context (all_elims params1 (nth prems2 i))] 1 |
758 resolve_tac context [Object_Logic.rulify context (all_elims params1 (nth prems2 i))] 1 |
764 THEN EVERY1 (map (prepare_prem context params2 prems2) prems1) |
759 THEN EVERY1 (map (prepare_prem context params2 prems2) prems1) |
765 end) *} |
760 end)\<close> |
766 |
761 |
767 text {* |
762 text \<open> |
768 Note that the tactic is now @{ML SUBPROOF}, not @{ML FOCUS in Subgoal} anymore. |
763 Note that the tactic is now @{ML SUBPROOF}, not @{ML FOCUS in Subgoal} anymore. |
769 The full proof of the introduction rule is as follows: |
764 The full proof of the introduction rule is as follows: |
770 *} |
765 \<close> |
771 |
766 |
772 lemma fresh_Lam: |
767 lemma fresh_Lam: |
773 shows "\<And>a b t. \<lbrakk>a \<noteq> b; fresh a t\<rbrakk> \<Longrightarrow> fresh a (Lam b t)" |
768 shows "\<And>a b t. \<lbrakk>a \<noteq> b; fresh a t\<rbrakk> \<Longrightarrow> fresh a (Lam b t)" |
774 apply(tactic {* expand_tac @{context} @{thms fresh_def} *}) |
769 apply(tactic \<open>expand_tac @{context} @{thms fresh_def}\<close>) |
775 apply(tactic {* prove_intro_tac 3 [fresh_pred] fresh_rules @{context} 1 *}) |
770 apply(tactic \<open>prove_intro_tac 3 [fresh_pred] fresh_rules @{context} 1\<close>) |
776 done |
771 done |
777 |
772 |
778 text {* |
773 text \<open> |
779 Phew!\ldots |
774 Phew!\ldots |
780 |
775 |
781 Unfortunately, not everything is done yet. If you look closely |
776 Unfortunately, not everything is done yet. If you look closely |
782 at the general principle outlined for the introduction rules in |
777 at the general principle outlined for the introduction rules in |
783 Section~\ref{sec:nutshell}, we have not yet dealt with the case where |
778 Section~\ref{sec:nutshell}, we have not yet dealt with the case where |
784 recursive premises have preconditions. The introduction rule |
779 recursive premises have preconditions. The introduction rule |
785 of the accessible part is such a rule. |
780 of the accessible part is such a rule. |
786 *} |
781 \<close> |
787 |
782 |
788 |
783 |
789 lemma accpartI: |
784 lemma accpartI: |
790 shows "\<And>R x. (\<And>y. R y x \<Longrightarrow> accpart R y) \<Longrightarrow> accpart R x" |
785 shows "\<And>R x. (\<And>y. R y x \<Longrightarrow> accpart R y) \<Longrightarrow> accpart R x" |
791 apply(tactic {* expand_tac @{context} @{thms accpart_def} *}) |
786 apply(tactic \<open>expand_tac @{context} @{thms accpart_def}\<close>) |
792 apply(tactic {* chop_test_tac [acc_pred] acc_rules @{context} 1 *}) |
787 apply(tactic \<open>chop_test_tac [acc_pred] acc_rules @{context} 1\<close>) |
793 apply(tactic {* apply_prem_tac 0 [acc_pred] acc_rules @{context} 1 *}) |
788 apply(tactic \<open>apply_prem_tac 0 [acc_pred] acc_rules @{context} 1\<close>) |
794 |
789 |
795 txt {* |
790 txt \<open> |
796 Here @{ML chop_test_tac} prints out the following |
791 Here @{ML chop_test_tac} prints out the following |
797 values for @{text "params1/2"} and @{text "prems1/2"} |
792 values for \<open>params1/2\<close> and \<open>prems1/2\<close> |
798 |
793 |
799 \begin{isabelle} |
794 \begin{isabelle} |
800 @{text "Params1 from the rule:"}\\ |
795 \<open>Params1 from the rule:\<close>\\ |
801 @{text "x"}\\ |
796 \<open>x\<close>\\ |
802 @{text "Params2 from the predicate:"}\\ |
797 \<open>Params2 from the predicate:\<close>\\ |
803 @{text "P"}\\ |
798 \<open>P\<close>\\ |
804 @{text "Prems1 from the rule:"}\\ |
799 \<open>Prems1 from the rule:\<close>\\ |
805 @{text "R ?y x \<Longrightarrow> \<forall>P. (\<forall>x. (\<forall>y. R y x \<longrightarrow> P y) \<longrightarrow> P x) \<longrightarrow> P ?y"}\\ |
800 \<open>R ?y x \<Longrightarrow> \<forall>P. (\<forall>x. (\<forall>y. R y x \<longrightarrow> P y) \<longrightarrow> P x) \<longrightarrow> P ?y\<close>\\ |
806 @{text "Prems2 from the predicate:"}\\ |
801 \<open>Prems2 from the predicate:\<close>\\ |
807 @{term "\<forall>x. (\<forall>y. R y x \<longrightarrow> P y) \<longrightarrow> P x"}\\ |
802 @{term "\<forall>x. (\<forall>y. R y x \<longrightarrow> P y) \<longrightarrow> P x"}\\ |
808 \end{isabelle} |
803 \end{isabelle} |
809 |
804 |
810 and after application of the introduction rule |
805 and after application of the introduction rule |
811 using @{ML apply_prem_tac}, we are in the goal state |
806 using @{ML apply_prem_tac}, we are in the goal state |
812 |
807 |
813 \begin{isabelle} |
808 \begin{isabelle} |
814 @{text "1."}~@{term "\<And>y. R y x \<Longrightarrow> P y"} |
809 \<open>1.\<close>~@{term "\<And>y. R y x \<Longrightarrow> P y"} |
815 \end{isabelle} |
810 \end{isabelle} |
816 |
811 |
817 |
812 |
818 *}(*<*)oops(*>*) |
813 \<close>(*<*)oops(*>*) |
819 |
814 |
820 text {* |
815 text \<open> |
821 In order to make progress, we have to use the precondition |
816 In order to make progress, we have to use the precondition |
822 @{text "R y x"} (in general there can be many of them). The best way |
817 \<open>R y x\<close> (in general there can be many of them). The best way |
823 to get a handle on these preconditions is to open up another subproof, |
818 to get a handle on these preconditions is to open up another subproof, |
824 since the preconditions will then be bound to @{text prems}. Therfore we |
819 since the preconditions will then be bound to \<open>prems\<close>. Therfore we |
825 modify the function @{ML prepare_prem} as follows |
820 modify the function @{ML prepare_prem} as follows |
826 *} |
821 \<close> |
827 |
822 |
828 ML %linenosgray{*fun prepare_prem params2 prems2 ctxt prem = |
823 ML %linenosgray\<open>fun prepare_prem params2 prems2 ctxt prem = |
829 SUBPROOF (fn {prems, ...} => |
824 SUBPROOF (fn {prems, ...} => |
830 let |
825 let |
831 val prem' = prems MRS prem |
826 val prem' = prems MRS prem |
832 in |
827 in |
833 resolve_tac ctxt [case Thm.prop_of prem' of |
828 resolve_tac ctxt [case Thm.prop_of prem' of |
834 _ $ (Const (@{const_name All}, _) $ _) => |
829 _ $ (Const (@{const_name All}, _) $ _) => |
835 prem' |> all_elims params2 |
830 prem' |> all_elims params2 |
836 |> imp_elims prems2 |
831 |> imp_elims prems2 |
837 | _ => prem'] 1 |
832 | _ => prem'] 1 |
838 end) ctxt *} |
833 end) ctxt\<close> |
839 |
834 |
840 text {* |
835 text \<open> |
841 In Line 4 we use the @{text prems} from the @{ML SUBPROOF} and resolve |
836 In Line 4 we use the \<open>prems\<close> from the @{ML SUBPROOF} and resolve |
842 them with @{text prem}. In the simple cases, that is where the @{text prem} |
837 them with \<open>prem\<close>. In the simple cases, that is where the \<open>prem\<close> |
843 comes from a non-recursive premise of the rule, @{text prems} will be |
838 comes from a non-recursive premise of the rule, \<open>prems\<close> will be |
844 just the empty list and the function @{ML_ind MRS in Drule} does nothing. Similarly, in the |
839 just the empty list and the function @{ML_ind MRS in Drule} does nothing. Similarly, in the |
845 cases where the recursive premises of the rule do not have preconditions. |
840 cases where the recursive premises of the rule do not have preconditions. |
846 In case there are preconditions, then Line 4 discharges them. After |
841 In case there are preconditions, then Line 4 discharges them. After |
847 that we can proceed as before, i.e., check whether the outermost |
842 that we can proceed as before, i.e., check whether the outermost |
848 connective is @{text "\<forall>"}. |
843 connective is \<open>\<forall>\<close>. |
849 |
844 |
850 The function @{ML prove_intro_tac} only needs to be changed so that it |
845 The function @{ML prove_intro_tac} only needs to be changed so that it |
851 gives the context to @{ML prepare_prem} (Line 8). The modified version |
846 gives the context to @{ML prepare_prem} (Line 8). The modified version |
852 is below. |
847 is below. |
853 *} |
848 \<close> |
854 |
849 |
855 ML %linenosgray{*fun prove_intro_tac i preds rules = |
850 ML %linenosgray\<open>fun prove_intro_tac i preds rules = |
856 SUBPROOF (fn {params, prems, context, ...} => |
851 SUBPROOF (fn {params, prems, context, ...} => |
857 let |
852 let |
858 val cparams = map snd params |
853 val cparams = map snd params |
859 val (params1, params2) = chop (length cparams - length preds) cparams |
854 val (params1, params2) = chop (length cparams - length preds) cparams |
860 val (prems1, prems2) = chop (length prems - length rules) prems |
855 val (prems1, prems2) = chop (length prems - length rules) prems |
861 in |
856 in |
862 resolve_tac context [Object_Logic.rulify context (all_elims params1 (nth prems2 i))] 1 |
857 resolve_tac context [Object_Logic.rulify context (all_elims params1 (nth prems2 i))] 1 |
863 THEN EVERY1 (map (prepare_prem params2 prems2 context) prems1) |
858 THEN EVERY1 (map (prepare_prem params2 prems2 context) prems1) |
864 end) *} |
859 end)\<close> |
865 |
860 |
866 text {* |
861 text \<open> |
867 With these two functions we can now also prove the introduction |
862 With these two functions we can now also prove the introduction |
868 rule for the accessible part. |
863 rule for the accessible part. |
869 *} |
864 \<close> |
870 |
865 |
871 lemma accpartI: |
866 lemma accpartI: |
872 shows "\<And>R x. (\<And>y. R y x \<Longrightarrow> accpart R y) \<Longrightarrow> accpart R x" |
867 shows "\<And>R x. (\<And>y. R y x \<Longrightarrow> accpart R y) \<Longrightarrow> accpart R x" |
873 apply(tactic {* expand_tac @{context} @{thms accpart_def} *}) |
868 apply(tactic \<open>expand_tac @{context} @{thms accpart_def}\<close>) |
874 apply(tactic {* prove_intro_tac 0 [acc_pred] acc_rules @{context} 1 *}) |
869 apply(tactic \<open>prove_intro_tac 0 [acc_pred] acc_rules @{context} 1\<close>) |
875 done |
870 done |
876 |
871 |
877 text {* |
872 text \<open> |
878 Finally we need two functions that string everything together. The first |
873 Finally we need two functions that string everything together. The first |
879 function is the tactic that performs the proofs. |
874 function is the tactic that performs the proofs. |
880 *} |
875 \<close> |
881 |
876 |
882 ML %linenosgray{*fun intro_tac defs rules preds i ctxt = |
877 ML %linenosgray\<open>fun intro_tac defs rules preds i ctxt = |
883 EVERY1 [Object_Logic.rulify_tac ctxt, |
878 EVERY1 [Object_Logic.rulify_tac ctxt, |
884 rewrite_goal_tac ctxt defs, |
879 rewrite_goal_tac ctxt defs, |
885 REPEAT o (resolve_tac ctxt [@{thm allI}, @{thm impI}]), |
880 REPEAT o (resolve_tac ctxt [@{thm allI}, @{thm impI}]), |
886 prove_intro_tac i preds rules ctxt]*} |
881 prove_intro_tac i preds rules ctxt]\<close> |
887 |
882 |
888 text {* |
883 text \<open> |
889 Lines 2 to 4 in this tactic correspond to the function @{ML expand_tac}. |
884 Lines 2 to 4 in this tactic correspond to the function @{ML expand_tac}. |
890 Some testcases for this tactic are: |
885 Some testcases for this tactic are: |
891 *} |
886 \<close> |
892 |
887 |
893 lemma even0_intro: |
888 lemma even0_intro: |
894 shows "even 0" |
889 shows "even 0" |
895 by (tactic {* intro_tac eo_defs eo_rules eo_preds 0 @{context} *}) |
890 by (tactic \<open>intro_tac eo_defs eo_rules eo_preds 0 @{context}\<close>) |
896 |
891 |
897 lemma evenS_intro: |
892 lemma evenS_intro: |
898 shows "\<And>m. odd m \<Longrightarrow> even (Suc m)" |
893 shows "\<And>m. odd m \<Longrightarrow> even (Suc m)" |
899 by (tactic {* intro_tac eo_defs eo_rules eo_preds 1 @{context} *}) |
894 by (tactic \<open>intro_tac eo_defs eo_rules eo_preds 1 @{context}\<close>) |
900 |
895 |
901 lemma fresh_App: |
896 lemma fresh_App: |
902 shows "\<And>a t s. \<lbrakk>fresh a t; fresh a s\<rbrakk> \<Longrightarrow> fresh a (App t s)" |
897 shows "\<And>a t s. \<lbrakk>fresh a t; fresh a s\<rbrakk> \<Longrightarrow> fresh a (App t s)" |
903 by (tactic {* |
898 by (tactic \<open> |
904 intro_tac @{thms fresh_def} fresh_rules [fresh_pred] 1 @{context} *}) |
899 intro_tac @{thms fresh_def} fresh_rules [fresh_pred] 1 @{context}\<close>) |
905 |
900 |
906 text {* |
901 text \<open> |
907 The second function sets up in Line 4 the goals to be proved (this is easy |
902 The second function sets up in Line 4 the goals to be proved (this is easy |
908 for the introduction rules since they are exactly the rules |
903 for the introduction rules since they are exactly the rules |
909 given by the user) and iterates @{ML intro_tac} over all |
904 given by the user) and iterates @{ML intro_tac} over all |
910 introduction rules. |
905 introduction rules. |
911 *} |
906 \<close> |
912 |
907 |
913 ML %linenosgray{*fun intros rules preds defs lthy = |
908 ML %linenosgray\<open>fun intros rules preds defs lthy = |
914 let |
909 let |
915 fun intros_aux (i, goal) = |
910 fun intros_aux (i, goal) = |
916 Goal.prove lthy [] [] goal |
911 Goal.prove lthy [] [] goal |
917 (fn {context, ...} => intro_tac defs rules preds i context) |
912 (fn {context, ...} => intro_tac defs rules preds i context) |
918 in |
913 in |
919 map_index intros_aux rules |
914 map_index intros_aux rules |
920 end*} |
915 end\<close> |
921 |
916 |
922 text {* |
917 text \<open> |
923 The iteration is done with the function @{ML_ind map_index in Library} since we |
918 The iteration is done with the function @{ML_ind map_index in Library} since we |
924 need the introduction rule together with its number (counted from |
919 need the introduction rule together with its number (counted from |
925 @{text 0}). This completes the code for the functions deriving the |
920 \<open>0\<close>). This completes the code for the functions deriving the |
926 reasoning infrastructure. It remains to implement some administrative |
921 reasoning infrastructure. It remains to implement some administrative |
927 code that strings everything together. |
922 code that strings everything together. |
928 *} |
923 \<close> |
929 |
924 |
930 subsection {* Administrative Functions *} |
925 subsection \<open>Administrative Functions\<close> |
931 |
926 |
932 text {* |
927 text \<open> |
933 We have produced various theorems (definitions, induction principles and |
928 We have produced various theorems (definitions, induction principles and |
934 introduction rules), but apart from the definitions, we have not yet |
929 introduction rules), but apart from the definitions, we have not yet |
935 registered them with the theorem database. This is what the functions |
930 registered them with the theorem database. This is what the functions |
936 @{ML_ind note in Local_Theory} does. |
931 @{ML_ind note in Local_Theory} does. |
937 |
932 |
938 |
933 |
939 For convenience, we use the following |
934 For convenience, we use the following |
940 three wrappers this function: |
935 three wrappers this function: |
941 *} |
936 \<close> |
942 |
937 |
943 ML %grayML{*fun note_many qname ((name, attrs), thms) = |
938 ML %grayML\<open>fun note_many qname ((name, attrs), thms) = |
944 Local_Theory.note ((Binding.qualify false qname name, attrs), thms) |
939 Local_Theory.note ((Binding.qualify false qname name, attrs), thms) |
945 |
940 |
946 fun note_single1 qname ((name, attrs), thm) = |
941 fun note_single1 qname ((name, attrs), thm) = |
947 note_many qname ((name, attrs), [thm]) |
942 note_many qname ((name, attrs), [thm]) |
948 |
943 |
949 fun note_single2 name attrs (qname, thm) = |
944 fun note_single2 name attrs (qname, thm) = |
950 note_many (Binding.name_of qname) ((name, attrs), [thm]) *} |
945 note_many (Binding.name_of qname) ((name, attrs), [thm])\<close> |
951 |
946 |
952 text {* |
947 text \<open> |
953 The function that ``holds everything together'' is @{text "add_inductive"}. |
948 The function that ``holds everything together'' is \<open>add_inductive\<close>. |
954 Its arguments are the specification of the predicates @{text "pred_specs"} |
949 Its arguments are the specification of the predicates \<open>pred_specs\<close> |
955 and the introduction rules @{text "rule_spec"}. |
950 and the introduction rules \<open>rule_spec\<close>. |
956 *} |
951 \<close> |
957 |
952 |
958 ML %linenosgray{*fun add_inductive pred_specs rule_specs lthy = |
953 ML %linenosgray\<open>fun add_inductive pred_specs rule_specs lthy = |
959 let |
954 let |
960 val mxs = map snd pred_specs |
955 val mxs = map snd pred_specs |
961 val pred_specs' = map fst pred_specs |
956 val pred_specs' = map fst pred_specs |
962 val prednames = map fst pred_specs' |
957 val prednames = map fst pred_specs' |
963 val preds = map (fn (p, ty) => Free (Binding.name_of p, ty)) pred_specs' |
958 val preds = map (fn (p, ty) => Free (Binding.name_of p, ty)) pred_specs' |