3 begin |
3 begin |
4 |
4 |
5 chapter {* Tactical Reasoning\label{chp:tactical} *} |
5 chapter {* Tactical Reasoning\label{chp:tactical} *} |
6 |
6 |
7 text {* |
7 text {* |
8 |
8 The main reason for descending to the ML-level of Isabelle is to be able to |
9 The main reason for descending to the ML-level of Isabelle is to be |
9 implement automatic proof procedures. Such proof procedures usually lessen |
10 able to implement automatic proof procedures. Such proof procedures usually |
10 considerably the burden of manual reasoning, for example, when introducing |
11 lessen considerably the burden of manual reasoning, for example, when |
11 new definitions. These proof procedures are centred around refining a goal |
12 introducing new definitions. These proof procedures are centred around |
12 state using tactics. This is similar to the \isacommand{apply}-style |
13 refining a goal state using tactics. This is similar to the @{text |
13 reasoning at the user level, where goals are modified in a sequence of proof |
14 apply}-style reasoning at the user level, where goals are modified in a |
14 steps until all of them are solved. However, there are also more structured |
15 sequence of proof steps until all of them are solved. However, there are |
15 operations available on the ML-level that help with the handling of |
16 also more structured operations available on the ML-level that help with |
16 variables and assumptions. |
17 the handling of variables and assumptions. |
|
18 |
17 |
19 *} |
18 *} |
20 |
19 |
21 section {* Basics of Reasoning with Tactics*} |
20 section {* Basics of Reasoning with Tactics*} |
22 |
21 |
57 @{text xs} that will be generalised once the goal is proved (in our case |
56 @{text xs} that will be generalised once the goal is proved (in our case |
58 @{text P} and @{text Q}). The @{text "tac"} is the tactic that proves the goal; |
57 @{text P} and @{text Q}). The @{text "tac"} is the tactic that proves the goal; |
59 it can make use of the local assumptions (there are none in this example). |
58 it can make use of the local assumptions (there are none in this example). |
60 The functions @{ML etac}, @{ML rtac} and @{ML atac} correspond to |
59 The functions @{ML etac}, @{ML rtac} and @{ML atac} correspond to |
61 @{text erule}, @{text rule} and @{text assumption}, respectively. |
60 @{text erule}, @{text rule} and @{text assumption}, respectively. |
62 The operator @{ML THEN} strings the tactics together. A difference |
61 The operator @{ML THEN} strings the tactics together. |
63 between the \isacommand{apply}-script and the ML-code is that the |
|
64 former causes the lemma to be stored under the name @{text "disj_swap"}, |
|
65 whereas the latter does not include any code for this. |
|
66 |
62 |
67 \begin{readmore} |
63 \begin{readmore} |
68 To learn more about the function @{ML Goal.prove} see \isccite{sec:results} |
64 To learn more about the function @{ML Goal.prove} see \isccite{sec:results} |
69 and the file @{ML_file "Pure/goal.ML"}. For more information about the |
65 and the file @{ML_file "Pure/goal.ML"}. For more information about the |
70 internals of goals see \isccite{sec:tactical-goals}. See @{ML_file |
66 internals of goals see \isccite{sec:tactical-goals}. See @{ML_file |
71 "Pure/tactic.ML"} and @{ML_file "Pure/tctical.ML"} for the code of basic |
67 "Pure/tactic.ML"} and @{ML_file "Pure/tctical.ML"} for the code of basic |
72 tactics and tactic combinators; see also Chapters 3 and 4 in the old |
68 tactics and tactic combinators; see also Chapters 3 and 4 in the old |
73 Isabelle Reference Manual. |
69 Isabelle Reference Manual. |
74 \end{readmore} |
70 \end{readmore} |
75 |
71 |
76 Note that we used antiquotations for referencing the theorems. We could also |
72 Note that we used antiquotations for referencing the theorems. Many theorems |
77 just have written @{ML "etac disjE 1"} and so on, but this is considered bad |
73 also have ML-bindings with the same name. Therefore, we could also just have |
78 style. The reason is that the binding for @{ML disjE} can be re-assigned by |
74 written @{ML "etac disjE 1"}, or in case there are no ML-binding obtained |
79 the user and thus one does not have complete control over which theorem is |
75 the theorem dynamically using the theorem @{ML thm}; for example @{ML "etac |
80 actually applied. This problem is nicely prevented by using antiquotations, |
76 (thm \"disjE\") 1"}. Both ways however are considered bad style. The reason |
81 because then the theorems are fixed statically at compile-time. |
77 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 applied. This problem is nicely prevented by using antiquotations, because |
|
80 then the theorems are fixed statically at compile-time. |
82 |
81 |
83 During the development of automatic proof procedures, you will often find it |
82 During the development of automatic proof procedures, you will often find it |
84 necessary to test a tactic on examples. This can be conveniently |
83 necessary to test a tactic on examples. This can be conveniently |
85 done with the command \isacommand{apply}@{text "(tactic \<verbopen> \<dots> \<verbclose>)"}. |
84 done with the command \isacommand{apply}@{text "(tactic \<verbopen> \<dots> \<verbclose>)"}. |
86 Consider the following sequence of tactics |
85 Consider the following sequence of tactics |
119 THEN' rtac @{thm disjI1} |
118 THEN' rtac @{thm disjI1} |
120 THEN' atac)*} |
119 THEN' atac)*} |
121 |
120 |
122 text {* |
121 text {* |
123 and then give the number for the subgoal explicitly when the tactic is |
122 and then give the number for the subgoal explicitly when the tactic is |
124 called. For every operator that combines tactics (@{ML THEN} is only one |
123 called. So in the next proof you can first discharge the second subgoal, and |
125 such operator), a primed version exists. So in the next proof you |
124 after that the first. |
126 can first discharge the second subgoal, and after that the first. |
|
127 *} |
125 *} |
128 |
126 |
129 lemma "P1 \<or> Q1 \<Longrightarrow> Q1 \<or> P1" |
127 lemma "P1 \<or> Q1 \<Longrightarrow> Q1 \<or> P1" |
130 and "P2 \<or> Q2 \<Longrightarrow> Q2 \<or> P2" |
128 and "P2 \<or> Q2 \<Longrightarrow> Q2 \<or> P2" |
131 apply(tactic {* foo_tac' 2 *}) |
129 apply(tactic {* foo_tac' 2 *}) |
132 apply(tactic {* foo_tac' 1 *}) |
130 apply(tactic {* foo_tac' 1 *}) |
133 done |
131 done |
134 |
132 |
135 text {* |
133 text {* |
136 This kind of addressing is more difficult to achieve when the goal is |
134 This kind of addressing is more difficult to achieve when the goal is |
137 hard-coded inside the tactic. |
135 hard-coded inside the tactic. For every operator that combines tactics |
|
136 (@{ML THEN} is only one such operator) a ``primed'' version exists. |
138 |
137 |
139 The tactics @{ML foo_tac} and @{ML foo_tac'} are very specific for |
138 The tactics @{ML foo_tac} and @{ML foo_tac'} are very specific for |
140 analysing goals being only of the form @{prop "P \<or> Q \<Longrightarrow> Q \<or> P"}. If the goal is not |
139 analysing goals being only of the form @{prop "P \<or> Q \<Longrightarrow> Q \<or> P"}. If the goal is not |
141 of this form, then @{ML foo_tac} throws the error message: |
140 of this form, then they throw the error message: |
142 |
141 |
143 \begin{isabelle} |
142 \begin{isabelle} |
144 @{text "*** empty result sequence -- proof command failed"}\\ |
143 @{text "*** empty result sequence -- proof command failed"}\\ |
145 @{text "*** At command \"apply\"."} |
144 @{text "*** At command \"apply\"."} |
146 \end{isabelle} |
145 \end{isabelle} |
147 |
146 |
148 Meaning the tactic failed. The reason for this error message is that tactics |
147 Meaning the tactics failed. The reason for this error message is that tactics |
149 are functions that map a goal state to a (lazy) sequence of successor states, |
148 are functions that map a goal state to a (lazy) sequence of successor states, |
150 hence the type of a tactic is: |
149 hence the type of a tactic is: |
151 |
150 |
152 @{text [display, gray] "type tactic = thm -> thm Seq.seq"} |
151 @{text [display, gray] "type tactic = thm -> thm Seq.seq"} |
153 |
152 |
154 It is custom that if a tactic fails, it should return the empty sequence: |
153 It is custom that if a tactic fails, it should return the empty sequence: |
155 your own tactics should not raise exceptions willy-nilly. |
154 therefore your own tactics should not raise exceptions willy-nilly. |
156 |
155 |
157 The simplest tactics are @{ML no_tac} and @{ML all_tac}. The first returns |
156 The simplest tactics are @{ML no_tac} and @{ML all_tac}. The first returns |
158 the empty sequence and is defined as |
157 the empty sequence and is defined as |
159 *} |
158 *} |
160 |
159 |
273 As can be seen, internally every goal state is an implication of the form |
272 As can be seen, internally every goal state is an implication of the form |
274 |
273 |
275 @{text[display] "A\<^isub>1 \<Longrightarrow> \<dots> \<Longrightarrow> A\<^isub>n \<Longrightarrow> (C)"} |
274 @{text[display] "A\<^isub>1 \<Longrightarrow> \<dots> \<Longrightarrow> A\<^isub>n \<Longrightarrow> (C)"} |
276 |
275 |
277 where @{term C} is the goal to be proved and the @{term "A\<^isub>i"} are the |
276 where @{term C} is the goal to be proved and the @{term "A\<^isub>i"} are the |
278 subgoals. So in the first step the goal state is always of the form |
277 subgoals. So after setting up the lemma, the goal state is always of the form |
279 @{text "C \<Longrightarrow> (C)"}. Since the goal @{term C} can potentially be an implication, |
278 @{text "C \<Longrightarrow> (C)"}. Since the goal @{term C} can potentially be an implication, |
280 there is a ``protector'' wrapped around it (in from of an outermost constant |
279 there is a ``protector'' wrapped around it (in from of an outermost constant |
281 @{text "Const (\"prop\", bool \<Rightarrow> bool)"} applied to each goal; |
280 @{text "Const (\"prop\", bool \<Rightarrow> bool)"} applied to each goal; |
282 however this constant is invisible in the print out above). This |
281 however this constant is invisible in the print out above). This |
283 prevents that premises are misinterpreted as open subgoals. |
282 prevents that premises of @{text C} are misinterpreted as open subgoals. |
284 While tactics can operate on the subgoals (the @{text "A\<^isub>i"} above), they |
283 While tactics can operate on the subgoals (the @{text "A\<^isub>i"} above), they |
285 are expected to leave the conclusion @{term C} intact, with the |
284 are expected to leave the conclusion @{term C} intact, with the |
286 exception of possibly instantiating schematic variables. |
285 exception of possibly instantiating schematic variables. |
287 |
286 |
288 *} |
287 *} |
289 |
288 |
290 section {* Simple Tactics *} |
289 section {* Simple Tactics *} |
291 |
290 |
292 text {* |
291 text {* |
293 As seen above, the function @{ML atac} corresponds to the assumption tactic. |
292 A simple tactic is @{ML print_tac}, which is useful for low-level debugging of tactics. |
|
293 It just prints out a message and the current goal state. |
|
294 *} |
|
295 |
|
296 lemma shows "False \<Longrightarrow> True" |
|
297 apply(tactic {* print_tac "foo message" *}) |
|
298 (*<*)oops(*>*) |
|
299 |
|
300 text {* |
|
301 Another simple tactic is the function @{ML atac}, which, as shown in the previous |
|
302 section, corresponds to the assumption command. |
294 *} |
303 *} |
295 |
304 |
296 lemma shows "P \<Longrightarrow> P" |
305 lemma shows "P \<Longrightarrow> P" |
297 apply(tactic {* atac 1 *}) |
306 apply(tactic {* atac 1 *}) |
298 done |
307 done |
325 @{subgoals [display]} |
334 @{subgoals [display]} |
326 \end{minipage}*} |
335 \end{minipage}*} |
327 (*<*)oops(*>*) |
336 (*<*)oops(*>*) |
328 |
337 |
329 text {* |
338 text {* |
330 As mentioned above, most basic tactics take a number as argument, which |
339 As mentioned in the previous section, most basic tactics take a number as |
331 addresses to subgoal they are analysing. |
340 argument, which addresses the subgoal they are analysing. In the proof below, |
|
341 we first break up the second subgoal by focusing on this subgoal first. |
332 *} |
342 *} |
333 |
343 |
334 lemma shows "Foo" and "P \<and> Q" |
344 lemma shows "Foo" and "P \<and> Q" |
335 apply(tactic {* rtac @{thm conjI} 2 *}) |
345 apply(tactic {* rtac @{thm conjI} 2 *}) |
336 txt {*\begin{minipage}{\textwidth} |
346 txt {*\begin{minipage}{\textwidth} |
337 @{subgoals [display]} |
347 @{subgoals [display]} |
338 \end{minipage}*} |
348 \end{minipage}*} |
339 (*<*)oops(*>*) |
349 (*<*)oops(*>*) |
340 |
350 |
341 text {* |
351 text {* |
342 Corresponding to @{ML rtac}, there is also the tactic @{ML resolve_tac}, which |
352 The function @{ML resolve_tac} is similar to @{ML rtac}, except that it |
343 however expects a list of theorems as arguments. From this list it will apply with |
353 expects a list of theorems as arguments. From this list it will apply the |
344 the first applicable theorem (later theorems that are also applicable can be |
354 first applicable theorem (later theorems that are also applicable can be |
345 explored via the lazy sequences mechanism). Given the abbreviation |
355 explored via the lazy sequences mechanism). Given the code |
346 *} |
356 *} |
347 |
357 |
348 ML{*val resolve_tac_xmp = resolve_tac [@{thm impI}, @{thm conjI}]*} |
358 ML{*val resolve_tac_xmp = resolve_tac [@{thm impI}, @{thm conjI}]*} |
349 |
359 |
350 text {* |
360 text {* |
360 \end{minipage}*} |
370 \end{minipage}*} |
361 (*<*)oops(*>*) |
371 (*<*)oops(*>*) |
362 |
372 |
363 text {* |
373 text {* |
364 Similarly versions exists for @{ML atac} (@{ML assume_tac}), @{ML etac} |
374 Similarly versions exists for @{ML atac} (@{ML assume_tac}), @{ML etac} |
365 (@{ML eresolve_tac}) and so on. |
375 (@{ML eresolve_tac}) and so on. |
366 |
376 |
367 The tactic @{ML print_tac} is useful for low-level debugging of tactics: it |
377 (FIXME: @{ML cut_facts_tac}) |
368 prints out a message and the current goal state. |
378 |
369 *} |
379 Since rules are applied using higher-order unification, an automatic proof |
370 |
380 procedure might become too fragile, if it just applies inference rules shown |
371 lemma shows "False \<Longrightarrow> True" |
381 in the fashion above. More constraints can be introduced by |
372 apply(tactic {* print_tac "foo message" *}) |
382 pre-instantiating theorems with other theorems. You can do this using the |
373 (*<*)oops(*>*) |
383 function @{ML RS}. For example |
374 |
|
375 text {* |
|
376 |
384 |
377 (FIXME explain RS MRS) |
385 @{ML_response_fake [display,gray] |
|
386 "@{thm disjI1} RS @{thm conjI}" "\<lbrakk>?P1; ?Q\<rbrakk> \<Longrightarrow> (?P1 \<or> ?Q1) \<and> ?Q"} |
|
387 |
|
388 instantiates the first premise of the @{text conjI}-rule with the |
|
389 rule @{text disjI1}. The function @{ML RSN} is similar, but |
|
390 takes a number and makes explicit which premise should be instantiated. |
|
391 To improve readability we are going use the following function |
|
392 *} |
|
393 |
|
394 ML{*fun no_vars ctxt thm = |
|
395 let |
|
396 val ((_, [thm']), _) = Variable.import_thms true [thm] ctxt |
|
397 in |
|
398 thm' |
|
399 end*} |
|
400 |
|
401 text {* |
|
402 to transform the schematic variables of a theorem into free variables. |
|
403 This means for the @{ML RS}-expression above: |
|
404 |
|
405 @{ML_response_fake [display,gray] |
|
406 "no_vars @{context} (@{thm disjI1} RS @{thm conjI})" "\<lbrakk>P; Q\<rbrakk> \<Longrightarrow> (P \<or> Qa) \<and> Q"} |
|
407 |
|
408 If you want to instantiate more than one premise, you can use the function |
|
409 @{ML MRS}: |
|
410 |
|
411 @{ML_response_fake [display,gray] |
|
412 "no_vars @{context} ([@{thm disjI1}, @{thm disjI2}] MRS @{thm conjI})" |
|
413 "\<lbrakk>P; Q\<rbrakk> \<Longrightarrow> (P \<or> Qa) \<and> (Pa \<or> Q)"} |
|
414 |
|
415 If you need to instantiate lists of theorems, you can use the |
|
416 functions @{ML RL} and @{ML MRL}. For example below every |
|
417 theorem in the first list is instantiated against every theorem |
|
418 in the second. |
|
419 |
|
420 @{ML_response_fake [display,gray] |
|
421 "[@{thm impI}, @{thm disjI2}] RL [@{thm conjI}, @{thm disjI1}]" |
|
422 "[\<lbrakk>P \<Longrightarrow> Q; Qa\<rbrakk> \<Longrightarrow> (P \<longrightarrow> Q) \<and> Qa, |
|
423 \<lbrakk>Q; Qa\<rbrakk> \<Longrightarrow> (P \<or> Q) \<and> Qa, |
|
424 (P \<Longrightarrow> Q) \<Longrightarrow> (P \<longrightarrow> Q) \<or> Qa, |
|
425 Q \<Longrightarrow> (P \<or> Q) \<or> Qa]"} |
|
426 |
|
427 \begin{readmore} |
|
428 The combinators for instantiating theorems are defined in @{ML_file "Pure/drule.ML"}. |
|
429 \end{readmore} |
378 |
430 |
379 Often proofs involve elaborate operations on assumptions and |
431 Often proofs involve elaborate operations on assumptions and |
380 @{text "\<And>"}-quantified variables. To do such operations on the ML-level |
432 @{text "\<And>"}-quantified variables. To do such operations on the ML-level |
381 using the basic tactics is very unwieldy and brittle. Some convenience and |
433 using the basic tactics is very unwieldy and brittle. Some convenience and |
382 safety is provided by the tactic @{ML SUBPROOF}. This tactic fixes the parameters |
434 safety is provided by the tactic @{ML SUBPROOF}. This tactic fixes the parameters |
383 and binds the various components of a proof state into a record. |
435 and binds the various components of a proof state into a record. |
|
436 To see what happens, assume the function defined in Figure~\ref{fig:sptac}, which |
|
437 takes a record as argument and just prints out the content of this record (using the |
|
438 string transformation functions defined in Section~\ref{sec:printing}). Consider |
|
439 now the proof |
384 *} |
440 *} |
385 |
441 |
386 text_raw{* |
442 text_raw{* |
387 \begin{figure} |
443 \begin{figure} |
388 \begin{isabelle} |
444 \begin{isabelle} |
433 premises: & @{term "A x y"} |
483 premises: & @{term "A x y"} |
434 \end{tabular} |
484 \end{tabular} |
435 \end{quote} |
485 \end{quote} |
436 |
486 |
437 Note in the actual output the brown colour of the variables @{term x} and |
487 Note in the actual output the brown colour of the variables @{term x} and |
438 @{term y}. Although parameters in the original goal, they are fixed inside |
488 @{term y}. Although they are parameters in the original goal, they are fixed inside |
439 the subproof. Similarly the schematic variable @{term z}. The assumption |
489 the subproof. Similarly the schematic variable @{term z}. The assumption |
440 @{prop "A x y"} is bound once as @{ML_type cterm} to the record-variable |
490 @{prop "A x y"} is bound as @{ML_type cterm} to the record-variable |
441 @{text asms} and another time as @{ML_type thm} to @{text prems}. |
491 @{text asms} but also as @{ML_type thm} to @{text prems}. |
442 |
492 |
443 Notice also that we had to append @{text "?"} to \isacommand{apply}. The |
493 Notice also that we had to append @{text "?"} to \isacommand{apply}. The |
444 reason is that @{ML SUBPROOF} normally expects that the subgoal is solved completely. |
494 reason is that @{ML SUBPROOF} normally expects that the subgoal is solved completely. |
445 Since in the function @{ML sp_tac} we returned the tactic @{ML no_tac}, the subproof |
495 Since in the function @{ML sp_tac} we returned the tactic @{ML no_tac}, the subproof |
446 obviously fails. The question-mark allows us to recover from this failure |
496 obviously fails. The question-mark allows us to recover from this failure |
494 |
544 |
495 Notice that @{ML atac'} calls @{ML resolve_tac} with the subgoal |
545 Notice that @{ML atac'} calls @{ML resolve_tac} with the subgoal |
496 number @{text "1"} and also the ``outer'' call to @{ML SUBPROOF} in |
546 number @{text "1"} and also the ``outer'' call to @{ML SUBPROOF} in |
497 the \isacommand{apply}-step uses @{text "1"}. Another advantage |
547 the \isacommand{apply}-step uses @{text "1"}. Another advantage |
498 of @{ML SUBGOAL} is that the addressing inside it is completely |
548 of @{ML SUBGOAL} is that the addressing inside it is completely |
499 local to the proof inside. It is therefore possible to also apply |
549 local to the subproof inside. It is therefore possible to also apply |
500 @{ML atac'} to the second goal: |
550 @{ML atac'} to the second goal: |
501 *} |
551 *} |
502 |
552 |
503 lemma shows "True" and "\<And>x y. \<lbrakk>B x y; A x y; C x y\<rbrakk> \<Longrightarrow> A x y" |
553 lemma shows "True" and "\<And>x y. \<lbrakk>B x y; A x y; C x y\<rbrakk> \<Longrightarrow> A x y" |
504 apply(tactic {* atac' @{context} 2 *}) |
554 apply(tactic {* atac' @{context} 2 *}) |
505 txt{* This gives: |
555 apply(rule TrueI) |
506 @{subgoals [display]} *} |
556 done |
507 (*<*)oops(*>*) |
557 |
508 |
558 |
509 |
559 text {* |
510 text {* |
560 \begin{readmore} |
|
561 The function @{ML SUBPROOF} is defined in @{ML_file "Pure/subgoal.ML"} and |
|
562 also described in \isccite{sec:results}. |
|
563 \end{readmore} |
|
564 |
511 A similar but less powerful function than @{ML SUBPROOF} is @{ML SUBGOAL}. |
565 A similar but less powerful function than @{ML SUBPROOF} is @{ML SUBGOAL}. |
512 It allows you to inspect a subgoal specified by a number. With this we can |
566 It allows you to inspect a specified subgoal. With this you can implement |
513 implement a little tactic that applies a rule corresponding to its |
567 a tactic that applies a rule according to its topmost connective (we only |
514 topmost connective. The tactic should only apply ``safe'' rules (that is |
568 analyse a few connectives). The tactic is as follows: |
515 which do not render the goal unprovable). For this we can write: |
|
516 *} |
569 *} |
517 |
570 |
518 ML %linenumbers{*fun select_tac (t,i) = |
571 ML %linenumbers{*fun select_tac (t,i) = |
519 case t of |
572 case t of |
520 @{term "Trueprop"} $ t' => select_tac (t',i) |
573 @{term "Trueprop"} $ t' => select_tac (t',i) |
522 | @{term "op \<longrightarrow>"} $ _ $ _ => rtac @{thm impI} i |
575 | @{term "op \<longrightarrow>"} $ _ $ _ => rtac @{thm impI} i |
523 | @{term "Not"} $ _ => rtac @{thm notI} i |
576 | @{term "Not"} $ _ => rtac @{thm notI} i |
524 | Const (@{const_name "All"}, _) $ _ => rtac @{thm allI} i |
577 | Const (@{const_name "All"}, _) $ _ => rtac @{thm allI} i |
525 | _ => all_tac*} |
578 | _ => all_tac*} |
526 |
579 |
527 lemma shows "A \<and> B" "A \<longrightarrow> B" "\<forall>x. C x" "D \<Longrightarrow> E" |
580 text {* |
|
581 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"} |
|
583 are not bropek up. In line 7, the pattern cannot be constructed using the |
|
584 @{text "@term"}-antiquotation, because that would fix the type of the |
|
585 quantified variable. In this case you really have to construct the pattern |
|
586 by using the term-constructors. The other cases work, because their type |
|
587 is always bool. In case that the goal does not fall into any of the categorories, |
|
588 then we chose to just return @{ML all_tac} (i.e., the tactic never fails). |
|
589 |
|
590 Let us now see how to apply this tactic. |
|
591 *} |
|
592 |
|
593 |
|
594 lemma shows "A \<and> B" and "A \<longrightarrow> B \<longrightarrow>C" and "\<forall>x. D x" and "E \<Longrightarrow> F" |
528 apply(tactic {* SUBGOAL select_tac 4 *}) |
595 apply(tactic {* SUBGOAL select_tac 4 *}) |
529 apply(tactic {* SUBGOAL select_tac 3 *}) |
596 apply(tactic {* SUBGOAL select_tac 3 *}) |
530 apply(tactic {* SUBGOAL select_tac 2 *}) |
597 apply(tactic {* SUBGOAL select_tac 2 *}) |
531 apply(tactic {* SUBGOAL select_tac 1 *}) |
598 apply(tactic {* SUBGOAL select_tac 1 *}) |
532 txt{* @{subgoals [display]} *} |
599 txt{* @{subgoals [display]} *} |
533 (*<*)oops(*>*) |
600 (*<*)oops(*>*) |
534 |
601 |
535 text {* |
602 text {* |
536 However, this example is contrived, as there are much simpler ways |
603 Note that we applied it in ``reverse'' order. This is a trick in |
537 to implement a proof procedure like the one above. They will be explained |
604 order to be independent from what subgoals the rule produced. If we had |
538 in the next section. |
605 it applied in the other order |
539 |
606 *} |
540 (Notice that we applied the goals in reverse order) |
607 |
541 |
608 lemma shows "A \<and> B" and "A \<longrightarrow> B \<longrightarrow>C" and "\<forall>x. D x" and "E \<Longrightarrow> F" |
542 A variant of @{ML SUBGOAL} is @{ML CSUBGOAL} which allows access to the goal |
609 apply(tactic {* SUBGOAL select_tac 1 *}) |
543 as @{ML_type cterm} instead of a @{ML_type term}. |
610 apply(tactic {* SUBGOAL select_tac 3 *}) |
544 *} |
611 apply(tactic {* SUBGOAL select_tac 4 *}) |
545 |
612 apply(tactic {* SUBGOAL select_tac 5 *}) |
546 |
613 (*<*)oops(*>*) |
547 section {* Operations on Tactics *} |
614 |
548 |
615 text {* |
549 text {* @{ML THEN} *} |
616 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 |
|
618 reverse application, on the other hand, is easy to implement. |
|
619 |
|
620 However, this example is contrived: there are much simpler ways to implement |
|
621 such proof procedure that analyses a goal according to its topmost |
|
622 connective. They will be explained in the next section. |
|
623 *} |
|
624 |
|
625 section {* Tactic Combinators *} |
|
626 |
|
627 text {* |
|
628 To be able to implement powerful tactics out of smaller component tactics, |
|
629 Isabelle provides tactic combinators. In the previous section we already |
|
630 used @{ML THEN} which strings two tactics together in sequence. For example: |
|
631 *} |
550 |
632 |
551 lemma shows "(Foo \<and> Bar) \<and> False" |
633 lemma shows "(Foo \<and> Bar) \<and> False" |
552 apply(tactic {* (rtac @{thm conjI} 1) |
634 apply(tactic {* rtac @{thm conjI} 1 THEN rtac @{thm conjI} 1 *}) |
553 THEN (rtac @{thm conjI} 1) *}) |
635 txt {* \begin{minipage}{\textwidth} |
554 txt {* @{subgoals [display]} *} |
636 @{subgoals [display]} |
555 (*<*)oops(*>*) |
637 \end{minipage} *} |
|
638 (*<*)oops(*>*) |
|
639 |
|
640 text {* |
|
641 If you want to avoid the hard-coded subgoal addressing, then you can use |
|
642 @{ML THEN'}. For example: |
|
643 *} |
|
644 |
|
645 lemma shows "(Foo \<and> Bar) \<and> False" |
|
646 apply(tactic {* (rtac @{thm conjI} THEN' rtac @{thm conjI}) 1 *}) |
|
647 txt {* \begin{minipage}{\textwidth} |
|
648 @{subgoals [display]} |
|
649 \end{minipage} *} |
|
650 (*<*)oops(*>*) |
|
651 |
|
652 text {* |
|
653 For most tactic combinators such a ``primed'' version exists. |
|
654 In what follows we will, whenever appropriate, prefer the primed version of |
|
655 the tactic combinator and omit to mention the simple one. |
|
656 |
|
657 With @{ML THEN} and @{ML THEN'} it must be guaranteed that both tactics |
|
658 sucessfully apply; otherwise the whole tactic will fail. If you want to |
|
659 try out either one tactic, then you can use @{ML ORELSE'}. For |
|
660 example |
|
661 *} |
556 |
662 |
557 ML{*val orelse_xmp = (rtac @{thm disjI1} ORELSE' rtac @{thm conjI})*} |
663 ML{*val orelse_xmp = (rtac @{thm disjI1} ORELSE' rtac @{thm conjI})*} |
|
664 |
|
665 text {* |
|
666 will first try out rule @{text disjI} and after that @{text conjI}. |
|
667 *} |
558 |
668 |
559 lemma shows "True \<and> False" and "Foo \<or> Bar" |
669 lemma shows "True \<and> False" and "Foo \<or> Bar" |
560 apply(tactic {* orelse_xmp 1 *}) |
670 apply(tactic {* orelse_xmp 1 *}) |
561 apply(tactic {* orelse_xmp 3 *}) |
671 apply(tactic {* orelse_xmp 3 *}) |
562 txt {* @{subgoals [display]} *} |
672 txt {* @{subgoals [display]} *} |
563 (*<*)oops(*>*) |
673 (*<*)oops(*>*) |
564 |
674 |
565 |
675 |
566 text {* |
676 text {* |
567 @{ML EVERY} @{ML REPEAT} @{ML DETERM} |
677 applies |
568 |
678 |
|
679 |
|
680 @{ML REPEAT} @{ML DETERM} |
|
681 |
|
682 *} |
|
683 |
|
684 section {* Rewriting and Simplifier Tactics *} |
|
685 |
|
686 text {* |
569 @{ML rewrite_goals_tac} |
687 @{ML rewrite_goals_tac} |
570 @{ML cut_facts_tac} |
|
571 @{ML ObjectLogic.full_atomize_tac} |
688 @{ML ObjectLogic.full_atomize_tac} |
572 @{ML ObjectLogic.rulify_tac} |
689 @{ML ObjectLogic.rulify_tac} |
573 @{ML resolve_tac} |
690 *} |
574 *} |
691 |
575 |
692 |
576 section {* Structured Proofs *} |
693 section {* Structured Proofs *} |
577 |
694 |
578 lemma True |
695 lemma True |
579 proof |
696 proof |