70 \end{readmore} |
70 \end{readmore} |
71 |
71 |
72 Note that we used antiquotations for referencing the theorems. Many theorems |
72 Note that we used antiquotations for referencing the theorems. Many theorems |
73 also have ML-bindings with the same name. Therefore, we could also just have |
73 also have ML-bindings with the same name. Therefore, we could also just have |
74 written @{ML "etac disjE 1"}, or in case there are no ML-binding obtained |
74 written @{ML "etac disjE 1"}, or in case there are no ML-binding obtained |
75 the theorem dynamically using the theorem @{ML thm}; for example @{ML "etac |
75 the theorem dynamically using the function @{ML thm}; for example |
76 (thm \"disjE\") 1"}. Both ways however are considered bad style. The reason |
76 @{ML "etac (thm \"disjE\") 1"}. Both ways however are considered bad style. |
|
77 The reason |
77 is that the binding for @{ML disjE} can be re-assigned by the user and thus |
78 is that the binding for @{ML disjE} can be re-assigned by the user and thus |
78 one does not have complete control over which theorem is actually |
79 one does not have complete control over which theorem is actually |
79 applied. This problem is nicely prevented by using antiquotations, because |
80 applied. This problem is nicely prevented by using antiquotations, because |
80 then the theorems are fixed statically at compile-time. |
81 then the theorems are fixed statically at compile-time. |
81 |
82 |
149 hence the type of a tactic is: |
150 hence the type of a tactic is: |
150 |
151 |
151 @{text [display, gray] "type tactic = thm -> thm Seq.seq"} |
152 @{text [display, gray] "type tactic = thm -> thm Seq.seq"} |
152 |
153 |
153 It is custom that if a tactic fails, it should return the empty sequence: |
154 It is custom that if a tactic fails, it should return the empty sequence: |
154 therefore your own tactics should not raise exceptions willy-nilly. |
155 therefore your own tactics should not raise exceptions willy-nilly. Only |
|
156 in very grave failure situations should a tactic raise the exception |
|
157 @{text THM}. |
155 |
158 |
156 The simplest tactics are @{ML no_tac} and @{ML all_tac}. The first returns |
159 The simplest tactics are @{ML no_tac} and @{ML all_tac}. The first returns |
157 the empty sequence and is defined as |
160 the empty sequence and is defined as |
158 *} |
161 *} |
159 |
162 |
160 ML{*fun no_tac thm = Seq.empty*} |
163 ML{*fun no_tac thm = Seq.empty*} |
161 |
164 |
162 text {* |
165 text {* |
163 which means @{ML no_tac} always fails. The second returns the given theorem wrapped |
166 which means @{ML no_tac} always fails. The second returns the given theorem wrapped |
164 as a single member sequence. It is defined as |
167 as a single member sequence; @{ML all_tac} is defined as |
165 *} |
168 *} |
166 |
169 |
167 ML{*fun all_tac thm = Seq.single thm*} |
170 ML{*fun all_tac thm = Seq.single thm*} |
168 |
171 |
169 text {* |
172 text {* |
170 which means @{ML all_tac} always succeeds (but also does not make any progress |
173 which means it always succeeds (but also does not make any progress |
171 with the proof). |
174 with the proof). |
172 |
175 |
173 The lazy list of possible successor states shows through at the user-level |
176 The lazy list of possible successor states shows through at the user-level |
174 of Isabelle when using the command \isacommand{back}. For instance in the |
177 of Isabelle when using the command \isacommand{back}. For instance in the |
175 following proof, there are two possibilities for how to apply |
178 following proof, there are two possibilities for how to apply |
176 @{ML foo_tac'}. |
179 @{ML foo_tac'}: either using the first assumption or the second. |
177 *} |
180 *} |
178 |
181 |
179 lemma "\<lbrakk>P \<or> Q; P \<or> Q\<rbrakk> \<Longrightarrow> Q \<or> P" |
182 lemma "\<lbrakk>P \<or> Q; P \<or> Q\<rbrakk> \<Longrightarrow> Q \<or> P" |
180 apply(tactic {* foo_tac' 1 *}) |
183 apply(tactic {* foo_tac' 1 *}) |
181 back |
184 back |
182 done |
185 done |
183 |
186 |
184 |
187 |
185 text {* |
188 text {* |
186 By using \isacommand{back}, we construct the proof that uses the |
189 By using \isacommand{back}, we construct the proof that uses the |
187 second assumption. In more interesting situations, different possibilities |
190 second assumption. In more interesting situations, only by exploring |
188 can lead to different proofs and even often need to be explored when |
191 different possibilities one might be able to find a proof. |
189 a first proof attempt is unsuccessful. |
|
190 |
192 |
191 \begin{readmore} |
193 \begin{readmore} |
192 See @{ML_file "Pure/General/seq.ML"} for the implementation of lazy |
194 See @{ML_file "Pure/General/seq.ML"} for the implementation of lazy |
193 sequences. However in day-to-day Isabelle programming, one rarely |
195 sequences. However in day-to-day Isabelle programming, one rarely |
194 constructs sequences explicitly, but uses the predefined functions |
196 constructs sequences explicitly, but uses the predefined functions |
273 |
275 |
274 @{text[display] "A\<^isub>1 \<Longrightarrow> \<dots> \<Longrightarrow> A\<^isub>n \<Longrightarrow> (C)"} |
276 @{text[display] "A\<^isub>1 \<Longrightarrow> \<dots> \<Longrightarrow> A\<^isub>n \<Longrightarrow> (C)"} |
275 |
277 |
276 where @{term C} is the goal to be proved and the @{term "A\<^isub>i"} are the |
278 where @{term C} is the goal to be proved and the @{term "A\<^isub>i"} are the |
277 subgoals. So after setting up the lemma, the goal state is always of the form |
279 subgoals. So after setting up the lemma, the goal state is always of the form |
278 @{text "C \<Longrightarrow> (C)"}. Since the goal @{term C} can potentially be an implication, |
280 @{text "C \<Longrightarrow> (C)"}, and when the proof is finished we are left with @{text "(C)"}. |
|
281 Since the goal @{term C} can potentially be an implication, |
279 there is a ``protector'' wrapped around it (in from of an outermost constant |
282 there is a ``protector'' wrapped around it (in from of an outermost constant |
280 @{text "Const (\"prop\", bool \<Rightarrow> bool)"} applied to each goal; |
283 @{text "Const (\"prop\", bool \<Rightarrow> bool)"} applied to each goal; |
281 however this constant is invisible in the print out above). This |
284 however this constant is invisible in the print out above). This |
282 prevents that premises of @{text C} are misinterpreted as open subgoals. |
285 prevents that premises of @{text C} are mis-interpreted as open subgoals. |
283 While tactics can operate on the subgoals (the @{text "A\<^isub>i"} above), they |
286 While tactics can operate on the subgoals (the @{text "A\<^isub>i"} above), they |
284 are expected to leave the conclusion @{term C} intact, with the |
287 are expected to leave the conclusion @{term C} intact, with the |
285 exception of possibly instantiating schematic variables. |
288 exception of possibly instantiating schematic variables. |
286 |
289 |
287 *} |
290 *} |
288 |
291 |
289 section {* Simple Tactics *} |
292 section {* Simple Tactics *} |
290 |
293 |
291 text {* |
294 text {* |
292 A simple tactic is @{ML print_tac}, which is useful for low-level debugging of tactics. |
295 A simple tactic is @{ML print_tac}, which is quite useful for low-level debugging of tactics. |
293 It just prints out a message and the current goal state. |
296 It just prints out a message and the current goal state. |
294 *} |
297 *} |
295 |
298 |
296 lemma shows "False \<Longrightarrow> True" |
299 lemma shows "False \<Longrightarrow> True" |
297 apply(tactic {* print_tac "foo message" *}) |
300 apply(tactic {* print_tac "foo message" *}) |
|
301 txt{*\begin{minipage}{\textwidth}\small |
|
302 @{text "foo message"}\\[3mm] |
|
303 @{prop "False \<Longrightarrow> True"}\\ |
|
304 @{text " 1. False \<Longrightarrow> True"}\\ |
|
305 \end{minipage} |
|
306 *} |
298 (*<*)oops(*>*) |
307 (*<*)oops(*>*) |
299 |
308 |
300 text {* |
309 text {* |
301 Another simple tactic is the function @{ML atac}, which, as shown in the previous |
310 Another simple tactic is the function @{ML atac}, which, as shown in the previous |
302 section, corresponds to the assumption command. |
311 section, corresponds to the assumption command. |
372 |
381 |
373 text {* |
382 text {* |
374 Similarly versions exists for @{ML atac} (@{ML assume_tac}), @{ML etac} |
383 Similarly versions exists for @{ML atac} (@{ML assume_tac}), @{ML etac} |
375 (@{ML eresolve_tac}) and so on. |
384 (@{ML eresolve_tac}) and so on. |
376 |
385 |
377 (FIXME: @{ML cut_facts_tac}) |
386 Another simple tactic is @{ML cut_facts_tac}. It inserts a list of theorems |
378 |
387 into the assumptions of the current goal state. For example: |
|
388 *} |
|
389 |
|
390 lemma shows "True \<noteq> False" |
|
391 apply(tactic {* cut_facts_tac [@{thm True_def}, @{thm False_def}] 1 *}) |
|
392 txt{*\begin{minipage}{\textwidth} |
|
393 @{subgoals [display]} |
|
394 \end{minipage}*} |
|
395 (*<*)oops(*>*) |
|
396 |
|
397 text {* |
379 Since rules are applied using higher-order unification, an automatic proof |
398 Since rules are applied using higher-order unification, an automatic proof |
380 procedure might become too fragile, if it just applies inference rules shown |
399 procedure might become too fragile, if it just applies inference rules shown |
381 in the fashion above. More constraints can be introduced by |
400 in the fashion above. More constraints can be introduced by |
382 pre-instantiating theorems with other theorems. You can do this using the |
401 pre-instantiating theorems with other theorems. You can do this using the |
383 function @{ML RS}. For example |
402 function @{ML RS}. For example |
384 |
403 |
385 @{ML_response_fake [display,gray] |
404 @{ML_response_fake [display,gray] |
386 "@{thm disjI1} RS @{thm conjI}" "\<lbrakk>?P1; ?Q\<rbrakk> \<Longrightarrow> (?P1 \<or> ?Q1) \<and> ?Q"} |
405 "@{thm disjI1} RS @{thm conjI}" "\<lbrakk>?P1; ?Q\<rbrakk> \<Longrightarrow> (?P1 \<or> ?Q1) \<and> ?Q"} |
387 |
406 |
388 instantiates the first premise of the @{text conjI}-rule with the |
407 instantiates the first premise of the @{text conjI}-rule with the |
389 rule @{text disjI1}. The function @{ML RSN} is similar, but |
408 rule @{text disjI1}. If this is impossible, as in the case of |
390 takes a number and makes explicit which premise should be instantiated. |
409 |
391 To improve readability we are going use the following function |
410 @{ML_response_fake_both [display,gray] |
|
411 "@{thm conjI} RS @{thm mp}" |
|
412 "*** Exception- THM (\"RSN: no unifiers\", 1, |
|
413 [\"\<lbrakk>?P; ?Q\<rbrakk> \<Longrightarrow> ?P \<and> ?Q\", \"\<lbrakk>?P \<longrightarrow> ?Q; ?P\<rbrakk> \<Longrightarrow> ?Q\"]) raised"} |
|
414 |
|
415 the function raises an exception. The function @{ML RSN} is similar, but |
|
416 takes a number as argument and thus you can make explicit which premise |
|
417 should be instantiated. |
|
418 |
|
419 To improve readability of the theorems we produce below, we shall use |
|
420 the following function |
392 *} |
421 *} |
393 |
422 |
394 ML{*fun no_vars ctxt thm = |
423 ML{*fun no_vars ctxt thm = |
395 let |
424 let |
396 val ((_, [thm']), _) = Variable.import_thms true [thm] ctxt |
425 val ((_, [thm']), _) = Variable.import_thms true [thm] ctxt |
397 in |
426 in |
398 thm' |
427 thm' |
399 end*} |
428 end*} |
400 |
429 |
401 text {* |
430 text {* |
402 to transform the schematic variables of a theorem into free variables. |
431 that transform the schematic variables of a theorem into free variables. |
403 This means for the @{ML RS}-expression above: |
432 This means for the first @{ML RS}-expression above: |
404 |
433 |
405 @{ML_response_fake [display,gray] |
434 @{ML_response_fake [display,gray] |
406 "no_vars @{context} (@{thm disjI1} RS @{thm conjI})" "\<lbrakk>P; Q\<rbrakk> \<Longrightarrow> (P \<or> Qa) \<and> Q"} |
435 "no_vars @{context} (@{thm disjI1} RS @{thm conjI})" "\<lbrakk>P; Q\<rbrakk> \<Longrightarrow> (P \<or> Qa) \<and> Q"} |
407 |
436 |
408 If you want to instantiate more than one premise, you can use the function |
437 If you want to instantiate more than one premise of a theorem, you can use |
409 @{ML MRS}: |
438 the function @{ML MRS}: |
410 |
439 |
411 @{ML_response_fake [display,gray] |
440 @{ML_response_fake [display,gray] |
412 "no_vars @{context} ([@{thm disjI1}, @{thm disjI2}] MRS @{thm conjI})" |
441 "no_vars @{context} ([@{thm disjI1}, @{thm disjI2}] MRS @{thm conjI})" |
413 "\<lbrakk>P; Q\<rbrakk> \<Longrightarrow> (P \<or> Qa) \<and> (Pa \<or> Q)"} |
442 "\<lbrakk>P; Q\<rbrakk> \<Longrightarrow> (P \<or> Qa) \<and> (Pa \<or> Q)"} |
414 |
443 |
415 If you need to instantiate lists of theorems, you can use the |
444 If you need to instantiate lists of theorems, you can use the |
416 functions @{ML RL} and @{ML MRL}. For example below every |
445 functions @{ML RL} and @{ML MRL}. For example in the code below |
417 theorem in the first list is instantiated against every theorem |
446 every theorem in the first list is instantiated against every |
418 in the second. |
447 theorem in the second. |
419 |
448 |
420 @{ML_response_fake [display,gray] |
449 @{ML_response_fake [display,gray] |
421 "[@{thm impI}, @{thm disjI2}] RL [@{thm conjI}, @{thm disjI1}]" |
450 "[@{thm impI}, @{thm disjI2}] RL [@{thm conjI}, @{thm disjI1}]" |
422 "[\<lbrakk>P \<Longrightarrow> Q; Qa\<rbrakk> \<Longrightarrow> (P \<longrightarrow> Q) \<and> Qa, |
451 "[\<lbrakk>P \<Longrightarrow> Q; Qa\<rbrakk> \<Longrightarrow> (P \<longrightarrow> Q) \<and> Qa, |
423 \<lbrakk>Q; Qa\<rbrakk> \<Longrightarrow> (P \<or> Q) \<and> Qa, |
452 \<lbrakk>Q; Qa\<rbrakk> \<Longrightarrow> (P \<or> Q) \<and> Qa, |
526 contains them as theorems. With this we can easily |
555 contains them as theorems. With this we can easily |
527 implement a tactic that almost behaves like @{ML atac}, namely: |
556 implement a tactic that almost behaves like @{ML atac}, namely: |
528 *} |
557 *} |
529 |
558 |
530 ML{*val atac' = SUBPROOF (fn {prems, ...} => resolve_tac prems 1)*} |
559 ML{*val atac' = SUBPROOF (fn {prems, ...} => resolve_tac prems 1)*} |
|
560 |
|
561 text {* |
|
562 If we apply it to the next lemma |
|
563 *} |
|
564 |
531 lemma shows "\<And>x y. \<lbrakk>B x y; A x y; C x y\<rbrakk> \<Longrightarrow> A x y" |
565 lemma shows "\<And>x y. \<lbrakk>B x y; A x y; C x y\<rbrakk> \<Longrightarrow> A x y" |
532 apply(tactic {* atac' @{context} 1 *}) |
566 apply(tactic {* atac' @{context} 1 *}) |
533 txt{* yields |
567 txt{* we get |
534 @{subgoals [display]} *} |
568 @{subgoals [display]} *} |
535 (*<*)oops(*>*) |
569 (*<*)oops(*>*) |
536 |
570 |
537 text {* |
571 text {* |
538 The restriction in this tactic is that it cannot instantiate any |
572 The restriction in this tactic is that it cannot instantiate any |
539 schematic variables. This might be seen as a defect, but is actually |
573 schematic variable. This might be seen as a defect, but it is actually |
540 an advantage in the situations for which @{ML SUBPROOF} was designed: |
574 an advantage in the situations for which @{ML SUBPROOF} was designed: |
541 the reason is that instantiation of schematic variables can affect |
575 the reason is that instantiation of schematic variables can affect |
542 several goals and can render them unprovable. @{ML SUBPROOF} is meant |
576 several goals and can render them unprovable. @{ML SUBPROOF} is meant |
543 to avoid this. |
577 to avoid this. |
544 |
578 |
545 Notice that @{ML atac'} calls @{ML resolve_tac} with the subgoal |
579 Notice that @{ML atac'} calls @{ML resolve_tac} with the subgoal |
546 number @{text "1"} and also the ``outer'' call to @{ML SUBPROOF} in |
580 number @{text "1"} and also the ``outer'' call to @{ML SUBPROOF} in |
547 the \isacommand{apply}-step uses @{text "1"}. Another advantage |
581 the \isacommand{apply}-step uses @{text "1"}. Another advantage |
548 of @{ML SUBGOAL} is that the addressing inside it is completely |
582 of @{ML SUBGOAL} is that the addressing inside it is completely |
549 local to the subproof inside. It is therefore possible to also apply |
583 local to the subproof inside. It is therefore possible to also apply |
550 @{ML atac'} to the second goal: |
584 @{ML atac'} to the second goal by just writing: |
551 *} |
585 *} |
552 |
586 |
553 lemma shows "True" and "\<And>x y. \<lbrakk>B x y; A x y; C x y\<rbrakk> \<Longrightarrow> A x y" |
587 lemma shows "True" and "\<And>x y. \<lbrakk>B x y; A x y; C x y\<rbrakk> \<Longrightarrow> A x y" |
554 apply(tactic {* atac' @{context} 2 *}) |
588 apply(tactic {* atac' @{context} 2 *}) |
555 apply(rule TrueI) |
589 apply(rule TrueI) |
577 | Const (@{const_name "All"}, _) $ _ => rtac @{thm allI} i |
612 | Const (@{const_name "All"}, _) $ _ => rtac @{thm allI} i |
578 | _ => all_tac*} |
613 | _ => all_tac*} |
579 |
614 |
580 text {* |
615 text {* |
581 In line 3 you need to decend under the outermost @{term "Trueprop"} in order |
616 In line 3 you need to decend under the outermost @{term "Trueprop"} in order |
582 to get to the connective you like to analyse. Otherwise goals @{prop "A \<and> B"} |
617 to get to the connective you like to analyse. Otherwise goals like @{prop "A \<and> B"} |
583 are not bropek up. In line 7, the pattern cannot be constructed using the |
618 are not properly analysed. While for the first four pattern we can use the |
584 @{text "@term"}-antiquotation, because that would fix the type of the |
619 @{text "@term"}-antiquotation, the pattern in Line 7 cannot be constructed |
585 quantified variable. In this case you really have to construct the pattern |
620 in this way. The reason is that an antiquotation would fix the type of the |
586 by using the term-constructors. The other cases work, because their type |
621 quantified variable. So you really have to construct the pattern |
587 is always bool. In case that the goal does not fall into any of the categorories, |
622 using the term-constructors. This is not necessary in other cases, because |
588 then we chose to just return @{ML all_tac} (i.e., the tactic never fails). |
623 their type is always something involving @{typ bool}. The final patter is |
589 |
624 for the case where the goal does not fall into any of the categorories before. |
590 Let us now see how to apply this tactic. |
625 In this case we chose to just return @{ML all_tac} (i.e., @{ML select_tac} |
|
626 never fails). |
|
627 |
|
628 Let us now see how to apply this tactic. Consider the four goals: |
591 *} |
629 *} |
592 |
630 |
593 |
631 |
594 lemma shows "A \<and> B" and "A \<longrightarrow> B \<longrightarrow>C" and "\<forall>x. D x" and "E \<Longrightarrow> F" |
632 lemma shows "A \<and> B" and "A \<longrightarrow> B \<longrightarrow>C" and "\<forall>x. D x" and "E \<Longrightarrow> F" |
595 apply(tactic {* SUBGOAL select_tac 4 *}) |
633 apply(tactic {* SUBGOAL select_tac 4 *}) |
596 apply(tactic {* SUBGOAL select_tac 3 *}) |
634 apply(tactic {* SUBGOAL select_tac 3 *}) |
597 apply(tactic {* SUBGOAL select_tac 2 *}) |
635 apply(tactic {* SUBGOAL select_tac 2 *}) |
598 apply(tactic {* SUBGOAL select_tac 1 *}) |
636 apply(tactic {* SUBGOAL select_tac 1 *}) |
599 txt{* @{subgoals [display]} *} |
637 txt{* \begin{minipage}{\textwidth} |
600 (*<*)oops(*>*) |
638 @{subgoals [display]} |
601 |
639 \end{minipage} *} |
602 text {* |
640 (*<*)oops(*>*) |
603 Note that we applied it in ``reverse'' order. This is a trick in |
641 |
604 order to be independent from what subgoals the rule produced. If we had |
642 text {* |
605 it applied in the other order |
643 where in all but the last the tactic applied an introduction rule. |
|
644 Note that we applied the tactic to subgoals in ``reverse'' order. |
|
645 This is a trick in order to be independent from what subgoals are |
|
646 that are produced by the rule. If we had it applied in the other order |
606 *} |
647 *} |
607 |
648 |
608 lemma shows "A \<and> B" and "A \<longrightarrow> B \<longrightarrow>C" and "\<forall>x. D x" and "E \<Longrightarrow> F" |
649 lemma shows "A \<and> B" and "A \<longrightarrow> B \<longrightarrow>C" and "\<forall>x. D x" and "E \<Longrightarrow> F" |
609 apply(tactic {* SUBGOAL select_tac 1 *}) |
650 apply(tactic {* SUBGOAL select_tac 1 *}) |
610 apply(tactic {* SUBGOAL select_tac 3 *}) |
651 apply(tactic {* SUBGOAL select_tac 3 *}) |
612 apply(tactic {* SUBGOAL select_tac 5 *}) |
653 apply(tactic {* SUBGOAL select_tac 5 *}) |
613 (*<*)oops(*>*) |
654 (*<*)oops(*>*) |
614 |
655 |
615 text {* |
656 text {* |
616 then we have to be careful to not apply the tactic to the two subgoals the |
657 then we have to be careful to not apply the tactic to the two subgoals the |
617 first goal produced. This can be messy in an automated proof script. The |
658 first goal produced. To do this can result in quite messy code. In contrast, |
618 reverse application, on the other hand, is easy to implement. |
659 the ``reverse application'' is easy to implement. |
619 |
660 |
620 However, this example is contrived: there are much simpler ways to implement |
661 However, this example is very contrived: there are much simpler methods to implement |
621 such proof procedure that analyses a goal according to its topmost |
662 such a proof procedure analying a goal according to its topmost |
622 connective. They will be explained in the next section. |
663 connective. These simpler methods use tactic combinators which will be explained |
|
664 in the next section. |
623 *} |
665 *} |
624 |
666 |
625 section {* Tactic Combinators *} |
667 section {* Tactic Combinators *} |
626 |
668 |
627 text {* |
669 text {* |
628 To be able to implement powerful tactics out of smaller component tactics, |
670 The purpose of tactic combinators is to build powerful tactics out of |
629 Isabelle provides tactic combinators. In the previous section we already |
671 smaller components. In the previous section we already used @{ML THEN} which |
630 used @{ML THEN} which strings two tactics together in sequence. For example: |
672 strings two tactics together in sequence. For example: |
631 *} |
673 *} |
632 |
674 |
633 lemma shows "(Foo \<and> Bar) \<and> False" |
675 lemma shows "(Foo \<and> Bar) \<and> False" |
634 apply(tactic {* rtac @{thm conjI} 1 THEN rtac @{thm conjI} 1 *}) |
676 apply(tactic {* rtac @{thm conjI} 1 THEN rtac @{thm conjI} 1 *}) |
635 txt {* \begin{minipage}{\textwidth} |
677 txt {* \begin{minipage}{\textwidth} |
637 \end{minipage} *} |
679 \end{minipage} *} |
638 (*<*)oops(*>*) |
680 (*<*)oops(*>*) |
639 |
681 |
640 text {* |
682 text {* |
641 If you want to avoid the hard-coded subgoal addressing, then you can use |
683 If you want to avoid the hard-coded subgoal addressing, then you can use |
642 @{ML THEN'}. For example: |
684 the ``primed'' version of @{ML THEN}, namely @{ML THEN'}. For example: |
643 *} |
685 *} |
644 |
686 |
645 lemma shows "(Foo \<and> Bar) \<and> False" |
687 lemma shows "(Foo \<and> Bar) \<and> False" |
646 apply(tactic {* (rtac @{thm conjI} THEN' rtac @{thm conjI}) 1 *}) |
688 apply(tactic {* (rtac @{thm conjI} THEN' rtac @{thm conjI}) 1 *}) |
647 txt {* \begin{minipage}{\textwidth} |
689 txt {* \begin{minipage}{\textwidth} |
648 @{subgoals [display]} |
690 @{subgoals [display]} |
649 \end{minipage} *} |
691 \end{minipage} *} |
650 (*<*)oops(*>*) |
692 (*<*)oops(*>*) |
651 |
693 |
652 text {* |
694 text {* |
653 For most tactic combinators such a ``primed'' version exists. |
695 For most tactic combinators such a ``primed'' version exists and |
654 In what follows we will, whenever appropriate, prefer the primed version of |
696 in what follows we will usually prefer it over the ``unprimed'' one. |
655 the tactic combinator and omit to mention the simple one. |
697 |
656 |
698 If there is a list of tactics that should all be tried out in |
657 With @{ML THEN} and @{ML THEN'} it must be guaranteed that both tactics |
699 sequence, you can use the combinator @{ML EVERY'}. For example |
658 sucessfully apply; otherwise the whole tactic will fail. If you want to |
700 the function @{ML foo_tac'} from page~\ref{tac:footacprime} can also |
659 try out either one tactic, then you can use @{ML ORELSE'}. For |
701 be written as |
660 example |
702 *} |
|
703 |
|
704 ML{*val foo_tac'' = EVERY' [etac @{thm disjE}, rtac @{thm disjI2}, |
|
705 atac, rtac @{thm disjI1}, atac]*} |
|
706 |
|
707 text {* |
|
708 There is even another variant for @{ML foo_tac''}: in automatic proof |
|
709 procedures (in contrast to tactics that might be called by the user) |
|
710 there are often long lists of tactics that are applied to the first |
|
711 subgoal. Instead of writing the code above and then calling |
|
712 @{ML "foo_tac'' 1"}, you can also just write |
|
713 *} |
|
714 |
|
715 ML{*val foo_tac1 = EVERY1 [etac @{thm disjE}, rtac @{thm disjI2}, |
|
716 atac, rtac @{thm disjI1}, atac]*} |
|
717 |
|
718 text {* |
|
719 With the combinators @{ML THEN'}, @{ML EVERY'} and @{ML EVERY1} it must be |
|
720 guaranteed that all component tactics sucessfully apply; otherwise the |
|
721 whole tactic will fail. If you rather want to try out a number of tactics, |
|
722 then you can use the combinator @{ML ORELSE'} for two tactics and @{ML FIRST'} |
|
723 (or @{ML FIRST1}) for a list of tactics. For example, the tactic |
661 *} |
724 *} |
662 |
725 |
663 ML{*val orelse_xmp = (rtac @{thm disjI1} ORELSE' rtac @{thm conjI})*} |
726 ML{*val orelse_xmp = (rtac @{thm disjI1} ORELSE' rtac @{thm conjI})*} |
664 |
727 |
665 text {* |
728 text {* |
666 will first try out rule @{text disjI} and after that @{text conjI}. |
729 will first try out whether rule @{text disjI} applies and after that |
|
730 whether @{text conjI}. To see this consider the proof: |
667 *} |
731 *} |
668 |
732 |
669 lemma shows "True \<and> False" and "Foo \<or> Bar" |
733 lemma shows "True \<and> False" and "Foo \<or> Bar" |
670 apply(tactic {* orelse_xmp 1 *}) |
734 apply(tactic {* orelse_xmp 1 *}) |
671 apply(tactic {* orelse_xmp 3 *}) |
735 apply(tactic {* orelse_xmp 3 *}) |
672 txt {* @{subgoals [display]} *} |
736 txt {* which results in the goal state |
673 (*<*)oops(*>*) |
737 |
674 |
738 \begin{minipage}{\textwidth} |
675 |
739 @{subgoals [display]} |
676 text {* |
740 \end{minipage} |
677 applies |
741 *} |
678 |
742 (*<*)oops(*>*) |
|
743 |
|
744 |
|
745 text {* |
|
746 Using @{ML FIRST'} we can write our @{ML select_tac} from Page~\ref{tac:selecttac} |
|
747 simply as follows: |
|
748 *} |
|
749 |
|
750 ML{*val select_tac' = FIRST' [rtac @{thm conjI}, rtac @{thm impI}, |
|
751 rtac @{thm notI}, rtac @{thm allI}, K all_tac]*} |
|
752 |
|
753 text {* |
|
754 Since we like to mimic the bahaviour of @{ML select_tac}, we must include |
|
755 @{ML all_tac} at the end (@{ML all_tac} must also be ``wrapped up'' using |
|
756 the @{ML K}-combinator as it does not take a subgoal number as argument). |
|
757 We can test the tactic on the same proof: |
|
758 *} |
|
759 |
|
760 lemma shows "A \<and> B" and "A \<longrightarrow> B \<longrightarrow>C" and "\<forall>x. D x" and "E \<Longrightarrow> F" |
|
761 apply(tactic {* select_tac' 4 *}) |
|
762 apply(tactic {* select_tac' 3 *}) |
|
763 apply(tactic {* select_tac' 2 *}) |
|
764 apply(tactic {* select_tac' 1 *}) |
|
765 txt{* \begin{minipage}{\textwidth} |
|
766 @{subgoals [display]} |
|
767 \end{minipage} *} |
|
768 (*<*)oops(*>*) |
|
769 |
|
770 text {* |
|
771 and obtain the same subgoals. Since this repeated application of a tactic |
|
772 to the reverse order of \emph{all} subgoals is quite common, there is |
|
773 the tactics combinator @{ML ALLGOALS} that simplifies this. Using this |
|
774 combinator we can simply write: *} |
|
775 |
|
776 lemma shows "A \<and> B" and "A \<longrightarrow> B \<longrightarrow>C" and "\<forall>x. D x" and "E \<Longrightarrow> F" |
|
777 apply(tactic {* ALLGOALS select_tac' *}) |
|
778 txt{* \begin{minipage}{\textwidth} |
|
779 @{subgoals [display]} |
|
780 \end{minipage} *} |
|
781 (*<*)oops(*>*) |
|
782 |
|
783 text {* |
|
784 We chose to write @{ML select_tac'} in such a way that it always succeeds. |
|
785 This can be potetially very confusing for the user in cases of goals |
|
786 of the form |
|
787 *} |
|
788 |
|
789 lemma shows "E \<Longrightarrow> F" |
|
790 apply(tactic {* select_tac' 1 *}) |
|
791 txt{* \begin{minipage}{\textwidth} |
|
792 @{subgoals [display]} |
|
793 \end{minipage} *} |
|
794 (*<*)oops(*>*) |
|
795 |
|
796 text {* |
|
797 where no rule applies. The reason is that the user has little chance |
|
798 to see whether progress in the proof has been made or not. We could simply |
|
799 remove @{ML "K all_tac"} from the end of the list. Then the tactic would |
|
800 only apply in cases where it can make some progress. But for the sake of |
|
801 argument, let us assume that this is not an option. In such cases, you |
|
802 can use the combinator @{ML CHANGED} to make sure the subgoal has been |
|
803 changed by the tactic. Because now |
|
804 *} |
|
805 |
|
806 lemma shows "E \<Longrightarrow> F" |
|
807 apply(tactic {* CHANGED (select_tac' 1) *})(*<*)?(*>*) |
|
808 txt{* results in the usual error message for empty result sequences. *} |
|
809 (*<*)oops(*>*) |
|
810 |
|
811 |
|
812 text {* |
679 |
813 |
680 @{ML REPEAT} @{ML DETERM} |
814 @{ML REPEAT} @{ML DETERM} |
|
815 |
|
816 @{ML CHANGED} |
681 |
817 |
682 *} |
818 *} |
683 |
819 |
684 section {* Rewriting and Simplifier Tactics *} |
820 section {* Rewriting and Simplifier Tactics *} |
685 |
821 |