11 (*>*) |
11 (*>*) |
12 |
12 |
13 chapter {* Tactical Reasoning\label{chp:tactical} *} |
13 chapter {* Tactical Reasoning\label{chp:tactical} *} |
14 |
14 |
15 text {* |
15 text {* |
16 One of the main reason for descending to the ML-level of Isabelle is to be able to |
16 One of the main reason for descending to the ML-level of Isabelle is to be |
17 implement automatic proof procedures. Such proof procedures usually lessen |
17 able to implement automatic proof procedures. Such proof procedures can |
18 considerably the burden of manual reasoning, for example, when introducing |
18 considerably lessen the burden of manual reasoning. They are centred around |
19 new definitions. These proof procedures are centred around refining a goal |
19 the idea of refining a goal state using tactics. This is similar to the |
20 state using tactics. This is similar to the \isacommand{apply}-style |
20 \isacommand{apply}-style reasoning at the user-level, where goals are |
21 reasoning at the user-level, where goals are modified in a sequence of proof |
21 modified in a sequence of proof steps until all of them are discharged. |
22 steps until all of them are solved. However, there are also more structured |
22 In this chapter we will explain simple tactics and how to combine them using |
23 operations available on the ML-level that help with the handling of |
23 tactic combinators. We also explain briefly the simplifier and conversions. |
24 variables and assumptions. |
|
25 *} |
24 *} |
26 |
25 |
27 |
26 |
28 section {* Basics of Reasoning with Tactics*} |
27 section {* Basics of Reasoning with Tactics*} |
29 |
28 |
30 text {* |
29 text {* |
31 To see how tactics work, let us first transcribe a simple \isacommand{apply}-style proof |
30 To see how tactics work, let us first transcribe a simple \isacommand{apply}-style proof |
32 into ML. Suppose the following proof. |
31 into ML. Suppose the following proof. |
33 *} |
32 *} |
34 |
33 |
35 lemma disj_swap: "P \<or> Q \<Longrightarrow> Q \<or> P" |
34 lemma disj_swap: |
|
35 shows "P \<or> Q \<Longrightarrow> Q \<or> P" |
36 apply(erule disjE) |
36 apply(erule disjE) |
37 apply(rule disjI2) |
37 apply(rule disjI2) |
38 apply(assumption) |
38 apply(assumption) |
39 apply(rule disjI1) |
39 apply(rule disjI1) |
40 apply(assumption) |
40 apply(assumption) |
55 THEN atac 1 |
55 THEN atac 1 |
56 THEN rtac @{thm disjI1} 1 |
56 THEN rtac @{thm disjI1} 1 |
57 THEN atac 1) |
57 THEN atac 1) |
58 end" "?P \<or> ?Q \<Longrightarrow> ?Q \<or> ?P"} |
58 end" "?P \<or> ?Q \<Longrightarrow> ?Q \<or> ?P"} |
59 |
59 |
60 To start the proof, the function @{ML_ind "Goal.prove"}~@{text "ctxt xs As C |
60 To start the proof, the function @{ML_ind prove in Goal} sets up a goal |
61 tac"} sets up a goal state for proving the goal @{text C} (that is @{prop "P |
61 state for proving the goal @{prop "P \<or> Q \<Longrightarrow> Q \<or> P"}. We can give this |
62 \<or> Q \<Longrightarrow> Q \<or> P"} in the proof at hand) under the assumptions @{text As} |
62 function some assumptions in the third argument (there are no assumption in |
63 (happens to be empty) with the variables @{text xs} that will be generalised |
63 the proof at hand). The second argument stands for a list of variables |
64 once the goal is proved (in our case @{text P} and @{text |
64 (given as strings). This list contains the variables that will be turned |
65 Q}).\footnote{FIXME: explain prove earlier} The @{text "tac"} is the tactic |
65 into schematic variables once the goal is proved (in our case @{text P} and |
66 that proves the goal; it can make use of the local assumptions (there are |
66 @{text Q}). The last argument is the tactic that proves the goal. This |
67 none in this example). The tactics @{ML_ind etac}, @{ML_ind rtac} and |
67 tactic can make use of the local assumptions (there are none in this |
68 @{ML_ind atac} in the code above correspond roughly to @{text erule}, @{text |
68 example). The tactics @{ML_ind etac}, @{ML_ind rtac} and @{ML_ind atac} in |
69 rule} and @{text assumption}, respectively. The operator @{ML_ind THEN} |
69 the code above correspond roughly to @{text erule}, @{text rule} and @{text |
70 strings the tactics together. |
70 assumption}, respectively. The combinator @{ML_ind THEN} strings the tactics |
|
71 together. |
71 |
72 |
72 \begin{readmore} |
73 \begin{readmore} |
73 To learn more about the function @{ML_ind prove in Goal} see |
74 To learn more about the function @{ML_ind prove in Goal} see |
74 \isccite{sec:results} and the file @{ML_file "Pure/goal.ML"}. See @{ML_file |
75 \isccite{sec:results} and the file @{ML_file "Pure/goal.ML"}. See @{ML_file |
75 "Pure/tactic.ML"} and @{ML_file "Pure/tactical.ML"} for the code of basic |
76 "Pure/tactic.ML"} and @{ML_file "Pure/tactical.ML"} for the code of basic |
77 Isabelle Reference Manual, and Chapter 3 in the Isabelle/Isar Implementation |
78 Isabelle Reference Manual, and Chapter 3 in the Isabelle/Isar Implementation |
78 Manual. |
79 Manual. |
79 \end{readmore} |
80 \end{readmore} |
80 |
81 |
81 Note that in the code above we use antiquotations for referencing the |
82 Note that in the code above we use antiquotations for referencing the |
82 theorems. Many theorems also have ML-bindings with the same name. Therefore, |
83 theorems. We could also just have written @{ML "etac disjE 1"}. The reason |
83 we could also just have written @{ML "etac disjE 1"}, or in case where there |
84 is that many of the basic theorems have a corresponding ML-binding: |
84 is no ML-binding obtain the theorem dynamically using the function @{ML |
85 |
85 thm}; for example \mbox{@{ML "etac (thm \"disjE\") 1"}}. Both ways however |
86 @{ML_response_fake [gray,display] |
86 are considered bad style! The reason is that the binding for @{ML disjE} can |
87 "disjE" |
87 be re-assigned by the user and thus one does not have complete control over |
88 "\<lbrakk>?P \<or> ?Q; ?P \<Longrightarrow> ?R; ?Q \<Longrightarrow> ?R\<rbrakk> \<Longrightarrow> ?R"} |
88 which theorem is actually applied. This problem is nicely prevented by using |
89 |
89 antiquotations, because then the theorems are fixed statically at |
90 In case where there is no ML-binding theorems can also be obtained dynamically using |
90 compile-time. |
91 the function @{ML thm} and the (string) name of the theorem; for example: |
|
92 |
|
93 @{ML_response_fake [gray,display] |
|
94 "thm \"disjE\"" |
|
95 "\<lbrakk>?P \<or> ?Q; ?P \<Longrightarrow> ?R; ?Q \<Longrightarrow> ?R\<rbrakk> \<Longrightarrow> ?R"} |
|
96 |
|
97 Both ways however are considered bad style! The reason is that the binding |
|
98 for @{ML disjE} can be re-assigned by the user and thus one does not have |
|
99 complete control over which theorem is actually applied. Similarly with the |
|
100 string @{text [quotes] "disjE"}. Although theorems in the theorem database |
|
101 must have a unique name, the string can stand for a dynamically updated |
|
102 theorem list. Also in this case we cannot be sure which theorem is applied. |
|
103 These problems can be nicely prevented by using antiquotations, because then |
|
104 the theorems are fixed statically at compile-time. |
|
105 |
91 |
106 |
92 During the development of automatic proof procedures, you will often find it |
107 During the development of automatic proof procedures, you will often find it |
93 necessary to test a tactic on examples. This can be conveniently done with |
108 necessary to test a tactic on examples. This can be conveniently done with |
94 the command \isacommand{apply}@{text "(tactic \<verbopen> \<dots> \<verbclose>)"}. |
109 the command \isacommand{apply}@{text "(tactic \<verbopen> \<dots> \<verbclose>)"}. |
95 Consider the following sequence of tactics |
110 Consider the following sequence of tactics |
128 THEN' atac |
144 THEN' atac |
129 THEN' rtac @{thm disjI1} |
145 THEN' rtac @{thm disjI1} |
130 THEN' atac)*}text_raw{*\label{tac:footacprime}*} |
146 THEN' atac)*}text_raw{*\label{tac:footacprime}*} |
131 |
147 |
132 text {* |
148 text {* |
133 where @{ML_ind THEN'} is used instead of @{ML THEN}. With @{ML foo_tac'} you can give |
149 where @{ML_ind THEN'} is used instead of @{ML THEN}. (For most combinators |
134 the number for the subgoal explicitly when the tactic is |
150 that combine tactics---@{ML THEN} is only one such combinator---a ``primed'' |
135 called. So in the next proof you can first discharge the second subgoal, and |
151 version exists.) With @{ML foo_tac'} you can give the number for the |
136 subsequently the first. |
152 subgoal explicitly when the tactic is called. So in the next proof you can |
137 *} |
153 first discharge the second subgoal, and subsequently the first. |
138 |
154 *} |
139 lemma "P1 \<or> Q1 \<Longrightarrow> Q1 \<or> P1" |
155 |
140 and "P2 \<or> Q2 \<Longrightarrow> Q2 \<or> P2" |
156 lemma |
|
157 shows "P1 \<or> Q1 \<Longrightarrow> Q1 \<or> P1" |
|
158 and "P2 \<or> Q2 \<Longrightarrow> Q2 \<or> P2" |
141 apply(tactic {* foo_tac' 2 *}) |
159 apply(tactic {* foo_tac' 2 *}) |
142 apply(tactic {* foo_tac' 1 *}) |
160 apply(tactic {* foo_tac' 1 *}) |
143 done |
161 done |
144 |
162 |
145 text {* |
163 text {* |
146 This kind of addressing is more difficult to achieve when the goal is |
164 This kind of addressing is more difficult to achieve when the goal is |
147 hard-coded inside the tactic. For most operators that combine tactics |
165 hard-coded inside the tactic. |
148 (@{ML THEN} is only one such operator) a ``primed'' version exists. |
166 |
149 |
167 The tactics @{ML foo_tac} and @{ML foo_tac'} are very specific for analysing |
150 The tactics @{ML foo_tac} and @{ML foo_tac'} are very specific for |
168 goals being only of the form @{prop "P \<or> Q \<Longrightarrow> Q \<or> P"}. If the goal is not of |
151 analysing goals being only of the form @{prop "P \<or> Q \<Longrightarrow> Q \<or> P"}. If the goal is not |
169 this form, then these tactics return the error message:\footnote{To be |
152 of this form, then these tactics return the error message: |
170 precise, tactics do not produce this error message, it originates from the |
|
171 \isacommand{apply} wrapper.} |
|
172 |
153 |
173 |
154 \begin{isabelle} |
174 \begin{isabelle} |
155 @{text "*** empty result sequence -- proof command failed"}\\ |
175 @{text "*** empty result sequence -- proof command failed"}\\ |
156 @{text "*** At command \"apply\"."} |
176 @{text "*** At command \"apply\"."} |
157 \end{isabelle} |
177 \end{isabelle} |
158 |
178 |
159 This means they failed.\footnote{To be precise, tactics do not produce this error |
179 This means they failed. The reason for this error message is that tactics |
160 message, it originates from the \isacommand{apply} wrapper.} The reason for this |
180 are functions mapping a goal state to a (lazy) sequence of successor |
161 error message is that tactics |
181 states. Hence the type of a tactic is: |
162 are functions mapping a goal state to a (lazy) sequence of successor states. |
|
163 Hence the type of a tactic is: |
|
164 *} |
182 *} |
165 |
183 |
166 ML{*type tactic = thm -> thm Seq.seq*} |
184 ML{*type tactic = thm -> thm Seq.seq*} |
167 |
185 |
168 text {* |
186 text {* |
300 *} |
320 *} |
301 (*<*)oops(*>*) |
321 (*<*)oops(*>*) |
302 text_raw {* |
322 text_raw {* |
303 \end{isabelle} |
323 \end{isabelle} |
304 \end{boxedminipage} |
324 \end{boxedminipage} |
305 \caption{The figure shows a proof where each intermediate goal state is |
325 \caption{The figure shows an Isabelle snippet of a proof where each |
306 printed by the Isabelle system and by @{ML my_print_tac}. The latter shows |
326 intermediate goal state is printed by the Isabelle system and by @{ML |
307 the goal state as represented internally (highlighted boxes). This |
327 my_print_tac}. The latter shows the goal state as represented internally |
308 tactic shows that every goal state in Isabelle is represented by a theorem: |
328 (highlighted boxes). This tactic shows that every goal state in Isabelle is |
309 when you start the proof of \mbox{@{text "\<lbrakk>A; B\<rbrakk> \<Longrightarrow> A \<and> B"}} the theorem is |
329 represented by a theorem: when you start the proof of \mbox{@{text "\<lbrakk>A; B\<rbrakk> \<Longrightarrow> |
310 @{text "(\<lbrakk>A; B\<rbrakk> \<Longrightarrow> A \<and> B) \<Longrightarrow> #(\<lbrakk>A; B\<rbrakk> \<Longrightarrow> A \<and> B)"}; when you finish the proof the |
330 A \<and> B"}} the theorem is @{text "(\<lbrakk>A; B\<rbrakk> \<Longrightarrow> A \<and> B) \<Longrightarrow> #(\<lbrakk>A; B\<rbrakk> \<Longrightarrow> A \<and> B)"}; when |
311 theorem is @{text "#(\<lbrakk>A; B\<rbrakk> \<Longrightarrow> A \<and> B)"}.\label{fig:goalstates}} |
331 you finish the proof the theorem is @{text "#(\<lbrakk>A; B\<rbrakk> \<Longrightarrow> A \<and> |
|
332 B)"}.\label{fig:goalstates}} |
312 \end{figure} |
333 \end{figure} |
313 *} |
334 *} |
314 |
335 |
315 text {* |
336 text {* |
316 which prints out the given theorem (using the string-function defined in |
337 which prints out the given theorem (using the string-function defined in |
317 Section~\ref{sec:printing}) and then behaves like @{ML all_tac}. With this |
338 Section~\ref{sec:printing}) and then behaves like @{ML all_tac}. With this |
318 tactic we are in the position to inspect every goal state in a |
339 tactic we are in the position to inspect every goal state in a proof. For |
319 proof. Consider now the proof in Figure~\ref{fig:goalstates}: as can be seen, |
340 this consider the proof in Figure~\ref{fig:goalstates}: as can be seen, |
320 internally every goal state is an implication of the form |
341 internally every goal state is an implication of the form |
321 |
342 |
322 @{text[display] "A\<^isub>1 \<Longrightarrow> \<dots> \<Longrightarrow> A\<^isub>n \<Longrightarrow> #C"} |
343 @{text[display] "A\<^isub>1 \<Longrightarrow> \<dots> \<Longrightarrow> A\<^isub>n \<Longrightarrow> #C"} |
323 |
344 |
324 where @{term C} is the goal to be proved and the @{term "A\<^isub>i"} are |
345 where @{term C} is the goal to be proved and the @{term "A\<^isub>i"} are |
347 |
368 |
348 text {* |
369 text {* |
349 Although Isabelle issues a warning message when stating goals involving |
370 Although Isabelle issues a warning message when stating goals involving |
350 meta-variables, it is possible to prove this theorem. The reason for the warning |
371 meta-variables, it is possible to prove this theorem. The reason for the warning |
351 message is that the proved theorem is not @{text "EQ_TRUE ?X"}, as one might |
372 message is that the proved theorem is not @{text "EQ_TRUE ?X"}, as one might |
352 expect, but @{thm test}: |
373 expect, but @{thm test}. We can test this with: |
353 |
374 |
354 \begin{isabelle} |
375 \begin{isabelle} |
355 \isacommand{thm}~@{thm [source] test}\\ |
376 \isacommand{thm}~@{thm [source] test}\\ |
356 @{text ">"}~@{thm test} |
377 @{text ">"}~@{thm test} |
357 \end{isabelle} |
378 \end{isabelle} |
358 |
379 |
359 As can be seen, the schematic variable @{text "?X"} has been instantiated inside the proof. |
380 The reason for this result is that the schematic variable @{text "?X"} |
|
381 is instantiated inside the proof and then the instantiation propagated |
|
382 to the ``outside''. |
360 |
383 |
361 \begin{readmore} |
384 \begin{readmore} |
362 For more information about the internals of goals see \isccite{sec:tactical-goals}. |
385 For more information about the internals of goals see \isccite{sec:tactical-goals}. |
363 \end{readmore} |
386 \end{readmore} |
364 |
387 |
365 *} |
388 *} |
366 |
389 |
367 section {* Simple Tactics\label{sec:simpletacs} *} |
390 section {* Simple Tactics\label{sec:simpletacs} *} |
368 |
391 |
369 text {* |
392 text {* |
370 Let us start with explaining the simple tactic @{ML_ind print_tac}, which is quite useful |
393 In this section we will describe more of the simple tactics in Isabelle. The |
|
394 first one is @{ML_ind print_tac}, which is quite useful |
371 for low-level debugging of tactics. It just prints out a message and the current |
395 for low-level debugging of tactics. It just prints out a message and the current |
372 goal state. Unlike @{ML my_print_tac} shown earlier, it prints the goal state |
396 goal state. Unlike @{ML my_print_tac} shown earlier, it prints the goal state |
373 as the user would see it. For example, processing the proof |
397 as the user would see it. For example, processing the proof |
374 *} |
398 *} |
375 |
399 |
376 lemma shows "False \<Longrightarrow> True" |
400 lemma |
|
401 shows "False \<Longrightarrow> True" |
377 apply(tactic {* print_tac "foo message" *}) |
402 apply(tactic {* print_tac "foo message" *}) |
378 txt{*gives:\medskip |
403 txt{*gives:\medskip |
379 |
404 |
380 \begin{minipage}{\textwidth}\small |
405 \begin{minipage}{\textwidth}\small |
381 @{text "foo message"}\\[3mm] |
406 @{text "foo message"}\\[3mm] |
385 *} |
410 *} |
386 (*<*)oops(*>*) |
411 (*<*)oops(*>*) |
387 |
412 |
388 text {* |
413 text {* |
389 A simple tactic for easy discharge of any proof obligations is |
414 A simple tactic for easy discharge of any proof obligations is |
390 @{ML_ind cheat_tac in Skip_Proof}. This tactic corresponds to |
415 @{ML_ind cheat_tac in Skip_Proof} in the structure @{ML_struct Skip_Proof}. |
391 the Isabelle command \isacommand{sorry} and is sometimes useful |
416 This tactic corresponds to the Isabelle command \isacommand{sorry} and is |
392 during the development of tactics. |
417 sometimes useful during the development of tactics. |
393 *} |
418 *} |
394 |
419 |
395 lemma shows "False" and "Goldbach_conjecture" |
420 lemma |
|
421 shows "False" and "Goldbach_conjecture" |
396 apply(tactic {* Skip_Proof.cheat_tac @{theory} *}) |
422 apply(tactic {* Skip_Proof.cheat_tac @{theory} *}) |
397 txt{*\begin{minipage}{\textwidth} |
423 txt{*\begin{minipage}{\textwidth} |
398 @{subgoals [display]} |
424 @{subgoals [display]} |
399 \end{minipage}*} |
425 \end{minipage}*} |
400 (*<*)oops(*>*) |
426 (*<*)oops(*>*) |
401 |
427 |
402 text {* |
428 text {* |
403 This tactic works however only if the quick-and-dirty mode of Isabelle |
429 This tactic works however only if the quick-and-dirty mode of Isabelle |
404 is switched on. |
430 is switched on. This is done automatically in the ``interactive |
405 |
431 mode'' of Isabelle, but must ne done manually in the ``batch mode''. |
406 Another simple tactic is the function @{ML_ind atac}, which, as shown in the previous |
432 |
407 section, corresponds to the assumption command. |
433 Another simple tactic is the function @{ML_ind atac}, which, as shown |
408 *} |
434 earlier, corresponds to the assumption method. |
409 |
435 *} |
410 lemma shows "P \<Longrightarrow> P" |
436 |
|
437 lemma |
|
438 shows "P \<Longrightarrow> P" |
411 apply(tactic {* atac 1 *}) |
439 apply(tactic {* atac 1 *}) |
412 txt{*\begin{minipage}{\textwidth} |
440 txt{*\begin{minipage}{\textwidth} |
413 @{subgoals [display]} |
441 @{subgoals [display]} |
414 \end{minipage}*} |
442 \end{minipage}*} |
415 (*<*)oops(*>*) |
443 (*<*)oops(*>*) |
470 @{ML dtac} (@{ML_ind dresolve_tac}), @{ML etac} |
503 @{ML dtac} (@{ML_ind dresolve_tac}), @{ML etac} |
471 (@{ML_ind eresolve_tac}) and so on. |
504 (@{ML_ind eresolve_tac}) and so on. |
472 |
505 |
473 |
506 |
474 Another simple tactic is @{ML_ind cut_facts_tac}. It inserts a list of theorems |
507 Another simple tactic is @{ML_ind cut_facts_tac}. It inserts a list of theorems |
475 into the assumptions of the current goal state. For example |
508 into the assumptions of the current goal state. Below we will insert the definitions |
476 *} |
509 for the constants @{term True} and @{term False}. So |
477 |
510 *} |
478 lemma shows "True \<noteq> False" |
511 |
|
512 lemma |
|
513 shows "True \<noteq> False" |
479 apply(tactic {* cut_facts_tac [@{thm True_def}, @{thm False_def}] 1 *}) |
514 apply(tactic {* cut_facts_tac [@{thm True_def}, @{thm False_def}] 1 *}) |
480 txt{*produces the goal state\medskip |
515 txt{*produces the goal state\medskip |
481 |
516 |
482 \begin{minipage}{\textwidth} |
517 \begin{minipage}{\textwidth} |
483 @{subgoals [display]} |
518 @{subgoals [display]} |
484 \end{minipage}*} |
519 \end{minipage}*} |
485 (*<*)oops(*>*) |
520 (*<*)oops(*>*) |
486 |
521 |
487 text {* |
522 text {* |
488 Since rules are applied using higher-order unification, an automatic proof |
|
489 procedure might become too fragile, if it just applies inference rules as |
|
490 shown above. The reason is that a number of rules introduce meta-variables |
|
491 into the goal state. Consider for example the proof |
|
492 *} |
|
493 |
|
494 lemma shows "\<forall>x \<in> A. P x \<Longrightarrow> Q x" |
|
495 apply(tactic {* dtac @{thm bspec} 1 *}) |
|
496 txt{*\begin{minipage}{\textwidth} |
|
497 @{subgoals [display]} |
|
498 \end{minipage}*} |
|
499 (*<*)oops(*>*) |
|
500 |
|
501 text {* |
|
502 where the application of rule @{text bspec} generates two subgoals involving the |
|
503 meta-variable @{text "?x"}. Now, if you are not careful, tactics |
|
504 applied to the first subgoal might instantiate this meta-variable in such a |
|
505 way that the second subgoal becomes unprovable. If it is clear what the @{text "?x"} |
|
506 should be, then this situation can be avoided by introducing a more |
|
507 constrained version of the @{text bspec}-rule. Such constraints can be given by |
|
508 pre-instantiating theorems with other theorems. One function to do this is |
|
509 @{ML_ind "RS"} |
|
510 |
|
511 @{ML_response_fake [display,gray] |
|
512 "@{thm disjI1} RS @{thm conjI}" "\<lbrakk>?P1; ?Q\<rbrakk> \<Longrightarrow> (?P1 \<or> ?Q1) \<and> ?Q"} |
|
513 |
|
514 which in the example instantiates the first premise of the @{text conjI}-rule |
|
515 with the rule @{text disjI1}. If the instantiation is impossible, as in the |
|
516 case of |
|
517 |
|
518 @{ML_response_fake_both [display,gray] |
|
519 "@{thm conjI} RS @{thm mp}" |
|
520 "*** Exception- THM (\"RSN: no unifiers\", 1, |
|
521 [\"\<lbrakk>?P; ?Q\<rbrakk> \<Longrightarrow> ?P \<and> ?Q\", \"\<lbrakk>?P \<longrightarrow> ?Q; ?P\<rbrakk> \<Longrightarrow> ?Q\"]) raised"} |
|
522 |
|
523 then the function raises an exception. The function @{ML_ind RSN} is similar to @{ML RS}, but |
|
524 takes an additional number as argument that makes explicit which premise |
|
525 should be instantiated. |
|
526 |
|
527 To improve readability of the theorems we shall produce below, we will use the |
|
528 function @{ML no_vars} from Section~\ref{sec:printing}, which transforms |
|
529 schematic variables into free ones. Using this function for the first @{ML |
|
530 RS}-expression above produces the more readable result: |
|
531 |
|
532 @{ML_response_fake [display,gray] |
|
533 "no_vars @{context} (@{thm disjI1} RS @{thm conjI})" "\<lbrakk>P; Q\<rbrakk> \<Longrightarrow> (P \<or> Qa) \<and> Q"} |
|
534 |
|
535 If you want to instantiate more than one premise of a theorem, you can use |
|
536 the function @{ML_ind MRS}: |
|
537 |
|
538 @{ML_response_fake [display,gray] |
|
539 "no_vars @{context} ([@{thm disjI1}, @{thm disjI2}] MRS @{thm conjI})" |
|
540 "\<lbrakk>P; Q\<rbrakk> \<Longrightarrow> (P \<or> Qa) \<and> (Pa \<or> Q)"} |
|
541 |
|
542 If you need to instantiate lists of theorems, you can use the |
|
543 functions @{ML RL} and @{ML_ind MRL}. For example in the code below, |
|
544 every theorem in the second list is instantiated with every |
|
545 theorem in the first. |
|
546 |
|
547 @{ML_response_fake [display,gray] |
|
548 "map (no_vars @{context}) |
|
549 ([@{thm impI}, @{thm disjI2}] RL [@{thm conjI}, @{thm disjI1}])" |
|
550 "[\<lbrakk>P \<Longrightarrow> Q; Qa\<rbrakk> \<Longrightarrow> (P \<longrightarrow> Q) \<and> Qa, |
|
551 \<lbrakk>Q; Qa\<rbrakk> \<Longrightarrow> (P \<or> Q) \<and> Qa, |
|
552 (P \<Longrightarrow> Q) \<Longrightarrow> (P \<longrightarrow> Q) \<or> Qa, |
|
553 Q \<Longrightarrow> (P \<or> Q) \<or> Qa]"} |
|
554 |
|
555 \begin{readmore} |
|
556 The combinators for instantiating theorems are defined in @{ML_file "Pure/drule.ML"}. |
|
557 \end{readmore} |
|
558 |
|
559 Often proofs on the ML-level involve elaborate operations on assumptions and |
523 Often proofs on the ML-level involve elaborate operations on assumptions and |
560 @{text "\<And>"}-quantified variables. To do such operations using the basic tactics |
524 @{text "\<And>"}-quantified variables. To do such operations using the basic tactics |
561 shown so far is very unwieldy and brittle. Some convenience and |
525 shown so far is very unwieldy and brittle. Some convenience and |
562 safety is provided by the functions @{ML_ind FOCUS in Subgoal} and |
526 safety is provided by the functions @{ML_ind FOCUS in Subgoal} and |
563 @{ML_ind SUBPROOF}. These tactics fix the parameters |
527 @{ML_ind SUBPROOF}. These tactics fix the parameters |
564 and bind the various components of a goal state to a record. |
528 and bind the various components of a goal state to a record. |
565 To see what happens, use the function defined in Figure~\ref{fig:sptac}, which |
529 To see what happens, suppose the function defined in Figure~\ref{fig:sptac}, which |
566 takes a record and just prints out the contents of this record. Consider |
530 takes a record and just prints out the contents of this record. Consider |
567 now the proof: |
531 now the proof: |
568 *} |
532 *} |
|
533 |
|
534 ML {* Subgoal.FOCUS *} |
569 |
535 |
570 text_raw{* |
536 text_raw{* |
571 \begin{figure}[t] |
537 \begin{figure}[t] |
572 \begin{minipage}{\textwidth} |
538 \begin{minipage}{\textwidth} |
573 \begin{isabelle} |
539 \begin{isabelle} |
574 *} |
540 *} |
575 |
541 |
576 |
|
577 ML{*fun foc_tac {prems, params, asms, concl, context, schematics} = |
542 ML{*fun foc_tac {prems, params, asms, concl, context, schematics} = |
578 let |
543 let |
579 val string_of_params = string_of_cterms context (map snd params) |
544 fun pairs1 f1 f2 xs = |
|
545 commas (map (fn (x, y) => f1 x ^ ":=" ^ f2 y) xs) |
|
546 |
|
547 fun pairs2 f xs = pairs1 f f xs |
|
548 |
|
549 val string_of_params = pairs1 I (string_of_cterm context) params |
580 val string_of_asms = string_of_cterms context asms |
550 val string_of_asms = string_of_cterms context asms |
581 val string_of_concl = string_of_cterm context concl |
551 val string_of_concl = string_of_cterm context concl |
582 val string_of_prems = string_of_thms_no_vars context prems |
552 val string_of_prems = string_of_thms_no_vars context prems |
583 val string_of_schms = string_of_cterms context (map fst (snd schematics)) |
553 val string_of_schms = pairs2 (string_of_cterm context) (snd schematics) |
584 |
554 |
585 val strs = ["params: " ^ string_of_params, |
555 val strs = ["params: " ^ string_of_params, |
586 "schematics: " ^ string_of_schms, |
556 "schematics: " ^ string_of_schms, |
587 "assumptions: " ^ string_of_asms, |
557 "assumptions: " ^ string_of_asms, |
588 "conclusion: " ^ string_of_concl, |
558 "conclusion: " ^ string_of_concl, |
589 "premises: " ^ string_of_prems] |
559 "premises: " ^ string_of_prems] |
599 in Section~\ref{sec:printing} for extracting strings from @{ML_type cterm}s |
569 in Section~\ref{sec:printing} for extracting strings from @{ML_type cterm}s |
600 and @{ML_type thm}s.\label{fig:sptac}} |
570 and @{ML_type thm}s.\label{fig:sptac}} |
601 \end{figure} |
571 \end{figure} |
602 *} |
572 *} |
603 |
573 |
604 lemma shows "\<And>x y. A x y \<Longrightarrow> B y x \<longrightarrow> C (?z y) x" |
574 lemma |
|
575 shows "\<And>x y. A x y \<Longrightarrow> B y x \<longrightarrow> C (?z y) x" |
605 apply(tactic {* Subgoal.FOCUS foc_tac @{context} 1 *}) |
576 apply(tactic {* Subgoal.FOCUS foc_tac @{context} 1 *}) |
606 |
577 |
607 txt {* |
578 txt {* |
608 The tactic produces the following printout: |
579 The tactic produces the following printout: |
609 |
580 |
610 \begin{quote}\small |
581 \begin{quote}\small |
611 \begin{tabular}{ll} |
582 \begin{tabular}{ll} |
612 params: & @{term x}, @{term y}\\ |
583 params: & @{text "x:=x"}, @{text "y:=y"}\\ |
613 schematics: & @{text ?z}\\ |
584 schematics: & @{text "?z:=z"}\\ |
614 assumptions: & @{term "A x y"}\\ |
585 assumptions: & @{term "A x y"}\\ |
615 conclusion: & @{term "B y x \<longrightarrow> C (z y) x"}\\ |
586 conclusion: & @{term "B y x \<longrightarrow> C (z y) x"}\\ |
616 premises: & @{term "A x y"} |
587 premises: & @{term "A x y"} |
617 \end{tabular} |
588 \end{tabular} |
618 \end{quote} |
589 \end{quote} |
619 |
590 |
620 (FIXME: Find out how nowadays the schematics are handled) |
591 The @{text params} and @{text schematics} stand or list of pairs where the left-hand |
621 |
592 side of @{text ":="} is replaced by the right-hand side inside the tactic. |
622 Notice in the actual output the brown colour of the variables @{term x}, |
593 Notice that in the actual output the brown colour of the variables @{term x}, |
623 and @{term y}. Although they are parameters in the original goal, they are fixed inside |
594 and @{term y}. Although they are parameters in the original goal, they are fixed inside |
624 the tactic. By convention these fixed variables are printed in brown colour. |
595 the tactic. By convention these fixed variables are printed in brown colour. |
625 Similarly the schematic variable @{text ?z}. The assumption, or premise, |
596 Similarly the schematic variable @{text ?z}. The assumption, or premise, |
626 @{prop "A x y"} is bound as @{ML_type cterm} to the record-variable |
597 @{prop "A x y"} is bound as @{ML_type cterm} to the record-variable |
627 @{text asms}, but also as @{ML_type thm} to @{text prems}. |
598 @{text asms}, but also as @{ML_type thm} to @{text prems}. |
770 |
746 |
771 Of course, this example is |
747 Of course, this example is |
772 contrived: there are much simpler methods available in Isabelle for |
748 contrived: there are much simpler methods available in Isabelle for |
773 implementing a tactic analysing a goal according to its topmost |
749 implementing a tactic analysing a goal according to its topmost |
774 connective. These simpler methods use tactic combinators, which we will |
750 connective. These simpler methods use tactic combinators, which we will |
775 explain in the next section. |
751 explain in the next section, but before that we will show how |
776 |
752 tactic application can be constraint. |
|
753 |
|
754 Since rules are applied using higher-order unification, an automatic proof |
|
755 procedure might become too fragile, if it just applies inference rules as |
|
756 shown above. The reason is that a number of rules introduce meta-variables |
|
757 into the goal state. Consider for example the proof |
|
758 *} |
|
759 |
|
760 lemma |
|
761 shows "\<forall>x \<in> A. P x \<Longrightarrow> Q x" |
|
762 apply(tactic {* dtac @{thm bspec} 1 *}) |
|
763 txt{*\begin{minipage}{\textwidth} |
|
764 @{subgoals [display]} |
|
765 \end{minipage}*} |
|
766 (*<*)oops(*>*) |
|
767 |
|
768 text {* |
|
769 where the application of rule @{text bspec} generates two subgoals involving the |
|
770 meta-variable @{text "?x"}. Now, if you are not careful, tactics |
|
771 applied to the first subgoal might instantiate this meta-variable in such a |
|
772 way that the second subgoal becomes unprovable. If it is clear what the @{text "?x"} |
|
773 should be, then this situation can be avoided by introducing a more |
|
774 constrained version of the @{text bspec}-rule. One way to give such |
|
775 constraints is by pre-instantiating theorems with other theorems. |
|
776 The function @{ML_ind "RS"}, for example, does this. |
|
777 |
|
778 @{ML_response_fake [display,gray] |
|
779 "@{thm disjI1} RS @{thm conjI}" "\<lbrakk>?P1; ?Q\<rbrakk> \<Longrightarrow> (?P1 \<or> ?Q1) \<and> ?Q"} |
|
780 |
|
781 In this example it instantiates the first premise of the @{text conjI}-rule |
|
782 with the rule @{text disjI1}. If the instantiation is impossible, as in the |
|
783 case of |
|
784 |
|
785 @{ML_response_fake_both [display,gray] |
|
786 "@{thm conjI} RS @{thm mp}" |
|
787 "*** Exception- THM (\"RSN: no unifiers\", 1, |
|
788 [\"\<lbrakk>?P; ?Q\<rbrakk> \<Longrightarrow> ?P \<and> ?Q\", \"\<lbrakk>?P \<longrightarrow> ?Q; ?P\<rbrakk> \<Longrightarrow> ?Q\"]) raised"} |
|
789 |
|
790 then the function raises an exception. The function @{ML_ind RSN} is similar to @{ML RS}, but |
|
791 takes an additional number as argument that makes explicit which premise |
|
792 should be instantiated. |
|
793 |
|
794 To improve readability of the theorems we shall produce below, we will use the |
|
795 function @{ML no_vars} from Section~\ref{sec:printing}, which transforms |
|
796 schematic variables into free ones. Using this function for the first @{ML |
|
797 RS}-expression above produces the more readable result: |
|
798 |
|
799 @{ML_response_fake [display,gray] |
|
800 "no_vars @{context} (@{thm disjI1} RS @{thm conjI})" "\<lbrakk>P; Q\<rbrakk> \<Longrightarrow> (P \<or> Qa) \<and> Q"} |
|
801 |
|
802 If you want to instantiate more than one premise of a theorem, you can use |
|
803 the function @{ML_ind MRS}: |
|
804 |
|
805 @{ML_response_fake [display,gray] |
|
806 "no_vars @{context} ([@{thm disjI1}, @{thm disjI2}] MRS @{thm conjI})" |
|
807 "\<lbrakk>P; Q\<rbrakk> \<Longrightarrow> (P \<or> Qa) \<and> (Pa \<or> Q)"} |
|
808 |
|
809 If you need to instantiate lists of theorems, you can use the |
|
810 functions @{ML RL} and @{ML_ind MRL}. For example in the code below, |
|
811 every theorem in the second list is instantiated with every |
|
812 theorem in the first. |
|
813 |
|
814 @{ML_response_fake [display,gray] |
|
815 "map (no_vars @{context}) |
|
816 ([@{thm impI}, @{thm disjI2}] RL [@{thm conjI}, @{thm disjI1}])" |
|
817 "[\<lbrakk>P \<Longrightarrow> Q; Qa\<rbrakk> \<Longrightarrow> (P \<longrightarrow> Q) \<and> Qa, |
|
818 \<lbrakk>Q; Qa\<rbrakk> \<Longrightarrow> (P \<or> Q) \<and> Qa, |
|
819 (P \<Longrightarrow> Q) \<Longrightarrow> (P \<longrightarrow> Q) \<or> Qa, |
|
820 Q \<Longrightarrow> (P \<or> Q) \<or> Qa]"} |
|
821 |
|
822 \begin{readmore} |
|
823 The combinators for instantiating theorems are defined in @{ML_file "Pure/drule.ML"}. |
|
824 \end{readmore} |
|
825 |
|
826 Higher-order unification is also often in the way when applying certain |
|
827 congruence theorems. For example we would expect that the theorem |
|
828 @{thm [source] cong} |
|
829 |
|
830 \begin{isabelle} |
|
831 \isacommand{thm}~@{thm [source] cong}\\ |
|
832 @{text "> "}~@{thm cong} |
|
833 \end{isabelle} |
|
834 |
|
835 is applicable in the following proof producing the subgoals |
|
836 @{term "t x = s u"} and @{term "y = w"}. |
|
837 *} |
|
838 |
|
839 lemma |
|
840 fixes x y u w::"'a" |
|
841 shows "t x y = s u w" |
|
842 apply(rule cong) |
|
843 txt{*\begin{minipage}{\textwidth} |
|
844 @{subgoals [display]} |
|
845 \end{minipage}*} |
|
846 (*<*)oops(*>*) |
|
847 |
|
848 text {* |
|
849 As you can see this is unfortunately \emph{not} the case. The problem is |
|
850 that higher-order unification produces an instantiation that is not the |
|
851 intended one. While we can use \isacommand{back} to interactively find the |
|
852 intended instantiation, this is not an option for an automatic proof |
|
853 procedure. Fortunately, the tactic @{ML_ind cong_tac in Cong_Tac} helps |
|
854 with applying congruence rules and finding the intended instantiation. |
|
855 *} |
|
856 |
|
857 lemma |
|
858 fixes x y u w::"'a" |
|
859 shows "t x y = s u w" |
|
860 apply(tactic {* Cong_Tac.cong_tac @{thm cong} 1 *}) |
|
861 txt{*\begin{minipage}{\textwidth} |
|
862 @{subgoals [display]} |
|
863 \end{minipage}*} |
|
864 (*<*)oops(*>*) |
|
865 |
|
866 text {* |
|
867 However, sometimes it is necessary to expicitly match a theroem against a proof |
|
868 state and in doing so finding manually an appropriate instantiation. Imagine |
|
869 you have the theorem |
|
870 *} |
|
871 |
|
872 lemma rule: |
|
873 shows "\<lbrakk>f = g; x = y\<rbrakk> \<Longrightarrow> R (f x) (g y)" |
|
874 sorry |
|
875 |
|
876 text {* |
|
877 and you want to apply it to the goal @{term "(t\<^isub>1 t\<^isub>2) \<le> |
|
878 (s\<^isub>1 s\<^isub>2)"}. Since in this theorem, all variables are |
|
879 schematic, we have a nasty higher-order unification problem and @{text rtac} |
|
880 will not be able to apply this rule as we want. However, in the proof below |
|
881 we are only interested where @{term R} is instantiated to a constant and |
|
882 similarly the instantiation for the other variables is ``obvious'' from the |
|
883 proof state. To use this rule we essentially match the conclusion of |
|
884 @{thm [source] rule} against the goal state reading of an instantiation for |
|
885 @{thm [source] rule}. For this the function @{ML_ind first_order_match in Thm} |
|
886 matches two @{ML_type cterm}s and produces, in the sucessful case, a matcher |
|
887 that can be used to instantiate the @{thm [source] rule}. The instantiation |
|
888 can be done with the function @{ML_ind instantiate in Drule}. To automate |
|
889 this we implement the following function. |
|
890 *} |
|
891 |
|
892 ML{*fun fo_rtac thm = |
|
893 Subgoal.FOCUS (fn {concl, ...} => |
|
894 let |
|
895 val concl_pat = Drule.strip_imp_concl (cprop_of thm) |
|
896 val insts = Thm.first_order_match (concl_pat, concl) |
|
897 in |
|
898 rtac (Drule.instantiate insts thm) 1 |
|
899 end)*} |
|
900 |
|
901 text {* |
|
902 Note that we use @{ML FOCUS in Subgoal} because we have directly access |
|
903 to the conclusion of the goal state and also because this function also |
|
904 takes care about correctly handling parameters that might be present |
|
905 in the goal state. An example for @{ML fo_rtac} is as follows. |
|
906 *} |
|
907 |
|
908 lemma |
|
909 shows "\<And>t\<^isub>1 s\<^isub>1 (t\<^isub>2::'a) (s\<^isub>2::'a). (t\<^isub>1 t\<^isub>2) \<le> (s\<^isub>1 s\<^isub>2)" |
|
910 apply(tactic {* fo_rtac @{thm rule} @{context} 1 *}) |
|
911 txt{*\begin{minipage}{\textwidth} |
|
912 @{subgoals [display]} |
|
913 \end{minipage}*} |
|
914 (*<*)oops(*>*) |
|
915 |
|
916 text {* |
|
917 We obtain the intended subgoals and also the parameters are correctly |
|
918 introduced in both of them. Such manual instantiations are quite frequently |
|
919 necessary in order to contrain the application of inference rules. Otherwise |
|
920 one ends up with ``wild'' higher-order unification problems that make |
|
921 automatic proofs fails. |
777 *} |
922 *} |
778 |
923 |
779 section {* Tactic Combinators *} |
924 section {* Tactic Combinators *} |
780 |
925 |
781 text {* |
926 text {* |
782 The purpose of tactic combinators is to build compound tactics out of |
927 The purpose of tactic combinators is to build compound tactics out of |
783 smaller tactics. In the previous section we already used @{ML THEN}, which |
928 smaller tactics. In the previous section we already used @{ML THEN}, which |
784 just strings together two tactics in a sequence. For example: |
929 just strings together two tactics in a sequence. For example: |
785 *} |
930 *} |
786 |
931 |
787 lemma shows "(Foo \<and> Bar) \<and> False" |
932 lemma |
|
933 shows "(Foo \<and> Bar) \<and> False" |
788 apply(tactic {* rtac @{thm conjI} 1 THEN rtac @{thm conjI} 1 *}) |
934 apply(tactic {* rtac @{thm conjI} 1 THEN rtac @{thm conjI} 1 *}) |
789 txt {* \begin{minipage}{\textwidth} |
935 txt {* \begin{minipage}{\textwidth} |
790 @{subgoals [display]} |
936 @{subgoals [display]} |
791 \end{minipage} *} |
937 \end{minipage} *} |
792 (*<*)oops(*>*) |
938 (*<*)oops(*>*) |