4 |
4 |
5 chapter {* Tactical Reasoning\label{chp:tactical} *} |
5 chapter {* Tactical Reasoning\label{chp:tactical} *} |
6 |
6 |
7 text {* |
7 text {* |
8 |
8 |
9 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 |
10 implement automatic proof procedures. Such proof procedures usually lessen |
10 able to implement automatic proof procedures. Such proof procedures usually |
11 considerably the burden of manual reasoning, for example, when introducing |
11 lessen considerably the burden of manual reasoning, for example, when |
12 new definitions. These proof procedures are centred around refining a goal |
12 introducing new definitions. These proof procedures are centred around |
13 state using tactics. This is similar to the @{text apply}-style reasoning at |
13 refining a goal state using tactics. This is similar to the @{text |
14 the user level, where goals are modified in a sequence of proof steps until |
14 apply}-style reasoning at the user level, where goals are modified in a |
15 all of them are solved. However, there are also more structured operations |
15 sequence of proof steps until all of them are solved. However, there are |
16 that help with handling of variables and assumptions. |
16 also more structured operations available on the ML-level that help with |
17 *} |
17 the handling of variables and assumptions. |
18 |
18 |
19 section {* Tactical Reasoning *} |
19 *} |
20 |
20 |
21 text {* |
21 section {* Basics of Reasoning with Tactics*} |
22 To see how tactics work, let us first transcribe a simple @{text apply}-style proof |
22 |
|
23 text {* |
|
24 To see how tactics work, let us first transcribe a simple \isacommand{apply}-style proof |
23 into ML. Consider the following proof. |
25 into ML. Consider the following proof. |
24 *} |
26 *} |
25 |
27 |
26 lemma disj_swap: "P \<or> Q \<Longrightarrow> Q \<or> P" |
28 lemma disj_swap: "P \<or> Q \<Longrightarrow> Q \<or> P" |
27 apply(erule disjE) |
29 apply(erule disjE) |
55 @{text xs} that will be generalised once the goal is proved (in our case |
57 @{text xs} that will be generalised once the goal is proved (in our case |
56 @{text P} and @{text Q}). The @{text "tac"} is the tactic that proves the goal; |
58 @{text P} and @{text Q}). The @{text "tac"} is the tactic that proves the goal; |
57 it can make use of the local assumptions (there are none in this example). |
59 it can make use of the local assumptions (there are none in this example). |
58 The functions @{ML etac}, @{ML rtac} and @{ML atac} correspond to |
60 The functions @{ML etac}, @{ML rtac} and @{ML atac} correspond to |
59 @{text erule}, @{text rule} and @{text assumption}, respectively. |
61 @{text erule}, @{text rule} and @{text assumption}, respectively. |
60 The operator @{ML THEN} strings the tactics together. |
62 The operator @{ML THEN} strings the tactics together. A difference |
|
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. |
61 |
66 |
62 \begin{readmore} |
67 \begin{readmore} |
63 To learn more about the function @{ML Goal.prove} see \isccite{sec:results} |
68 To learn more about the function @{ML Goal.prove} see \isccite{sec:results} |
64 and the file @{ML_file "Pure/goal.ML"}. For more information about the |
69 and the file @{ML_file "Pure/goal.ML"}. For more information about the |
65 internals of goals see \isccite{sec:tactical-goals}. See @{ML_file |
70 internals of goals see \isccite{sec:tactical-goals}. See @{ML_file |
73 style. The reason is that the binding for @{ML disjE} can be re-assigned by |
78 style. The reason is that the binding for @{ML disjE} can be re-assigned by |
74 the user and thus one does not have complete control over which theorem is |
79 the user and thus one does not have complete control over which theorem is |
75 actually applied. This problem is nicely prevented by using antiquotations, |
80 actually applied. This problem is nicely prevented by using antiquotations, |
76 because then the theorems are fixed statically at compile-time. |
81 because then the theorems are fixed statically at compile-time. |
77 |
82 |
78 During the development of automatic proof procedures, it will often be necessary |
83 During the development of automatic proof procedures, you will often find it |
79 to test a tactic on examples. This can be conveniently |
84 necessary to test a tactic on examples. This can be conveniently |
80 done with the command \isacommand{apply}@{text "(tactic \<verbopen> \<dots> \<verbclose>)"}. |
85 done with the command \isacommand{apply}@{text "(tactic \<verbopen> \<dots> \<verbclose>)"}. |
81 Consider the following sequence of tactics |
86 Consider the following sequence of tactics |
82 *} |
87 *} |
83 |
88 |
84 ML{*val foo_tac = |
89 ML{*val foo_tac = |
94 apply(tactic {* foo_tac *}) |
99 apply(tactic {* foo_tac *}) |
95 done |
100 done |
96 |
101 |
97 text {* |
102 text {* |
98 By using @{text "tactic \<verbopen> \<dots> \<verbclose>"} in the apply-step, |
103 By using @{text "tactic \<verbopen> \<dots> \<verbclose>"} in the apply-step, |
99 you can call @{ML foo_tac} or any function that returns a tactic from the |
104 you can call from the user level of Isabelle the tactic @{ML foo_tac} or |
100 user level of Isabelle. |
105 any other function that returns a tactic. |
101 |
106 |
102 As can be seen, each tactic in @{ML foo_tac} has a hard-coded number that |
107 The tactic @{ML foo_tac} is just a sequence of simple tactics stringed |
103 stands for the subgoal analysed by the tactic. In our case, we only focus on the first |
108 together by @{ML THEN}. As can be seen, each simple tactic in @{ML foo_tac} |
104 subgoal. This is sometimes wanted, but usually not. To avoid the explicit numbering in the |
109 has a hard-coded number that stands for the subgoal analysed by the |
105 tactic, you can write |
110 tactic (@{text "1"} stands for the first, or top-most, subgoal). This is |
|
111 sometimes wanted, but usually not. To avoid the explicit numbering in |
|
112 the tactic, you can write |
106 *} |
113 *} |
107 |
114 |
108 ML{*val foo_tac' = |
115 ML{*val foo_tac' = |
109 (etac @{thm disjE} |
116 (etac @{thm disjE} |
110 THEN' rtac @{thm disjI2} |
117 THEN' rtac @{thm disjI2} |
112 THEN' rtac @{thm disjI1} |
119 THEN' rtac @{thm disjI1} |
113 THEN' atac)*} |
120 THEN' atac)*} |
114 |
121 |
115 text {* |
122 text {* |
116 and then give the number for the subgoal explicitly when the tactic is |
123 and then give the number for the subgoal explicitly when the tactic is |
117 called. For every operator that combines tactics, such a primed version |
124 called. For every operator that combines tactics (@{ML THEN} is only one |
118 exists. So in the next proof we can first discharge the second subgoal, |
125 such operator), a primed version exists. So in the next proof you |
119 and after that the first. |
126 can first discharge the second subgoal, and after that the first. |
120 *} |
127 *} |
121 |
128 |
122 lemma "P1 \<or> Q1 \<Longrightarrow> Q1 \<or> P1" |
129 lemma "P1 \<or> Q1 \<Longrightarrow> Q1 \<or> P1" |
123 and "P2 \<or> Q2 \<Longrightarrow> Q2 \<or> P2" |
130 and "P2 \<or> Q2 \<Longrightarrow> Q2 \<or> P2" |
124 apply(tactic {* foo_tac' 2 *}) |
131 apply(tactic {* foo_tac' 2 *}) |
125 apply(tactic {* foo_tac' 1 *}) |
132 apply(tactic {* foo_tac' 1 *}) |
126 done |
133 done |
127 |
134 |
128 text {* |
135 text {* |
129 (FIXME: maybe add something about how each goal state is interpreted |
136 This kind of addressing is more difficult to achieve when the goal is |
130 as a theorem) |
137 hard-coded inside the tactic. |
131 |
138 |
132 The tactic @{ML foo_tac} (and @{ML foo_tac'}) are very specific for |
139 The tactics @{ML foo_tac} and @{ML foo_tac'} are very specific for |
133 analysing goals only of the form @{prop "P \<or> Q \<Longrightarrow> Q \<or> P"}. If the goal is not |
140 analysing goals being only of the form @{prop "P \<or> Q \<Longrightarrow> Q \<or> P"}. If the goal is not |
134 of this form, then @{ML foo_tac} throws the error message: |
141 of this form, then @{ML foo_tac} throws the error message: |
135 |
142 |
136 \begin{isabelle} |
143 \begin{isabelle} |
137 @{text "*** empty result sequence -- proof command failed"}\\ |
144 @{text "*** empty result sequence -- proof command failed"}\\ |
138 @{text "*** At command \"apply\"."} |
145 @{text "*** At command \"apply\"."} |
139 \end{isabelle} |
146 \end{isabelle} |
140 |
147 |
141 Meaning the tactic failed. The reason for this error message is that tactics |
148 Meaning the tactic failed. The reason for this error message is that tactics |
142 are functions that map a goal state to a (lazy) sequence of successor states, |
149 are functions that map a goal state to a (lazy) sequence of successor states, |
143 hence the type of a tactic is |
150 hence the type of a tactic is: |
144 |
151 |
145 @{text [display, gray] "type tactic = thm -> thm Seq.seq"} |
152 @{text [display, gray] "type tactic = thm -> thm Seq.seq"} |
146 |
153 |
147 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: |
148 tactics should not raise exceptions willy-nilly. |
155 your own tactics should not raise exceptions willy-nilly. |
|
156 |
|
157 The simplest tactics are @{ML no_tac} and @{ML all_tac}. The first returns |
|
158 the empty sequence and is defined as |
|
159 *} |
|
160 |
|
161 ML{*fun no_tac thm = Seq.empty*} |
|
162 |
|
163 text {* |
|
164 which means @{ML no_tac} always fails. The second returns the given theorem wrapped |
|
165 as a single member sequence. It is defined as |
|
166 *} |
|
167 |
|
168 ML{*fun all_tac thm = Seq.single thm*} |
|
169 |
|
170 text {* |
|
171 which means @{ML all_tac} always succeeds (but also does not make any progress |
|
172 with the proof). |
149 |
173 |
150 The lazy list of possible successor states shows through to the user-level |
174 The lazy list of possible successor states shows through to the user-level |
151 of Isabelle when using the command \isacommand{back}. For instance in the |
175 of Isabelle when using the command \isacommand{back}. For instance in the |
152 following proof, there are two possibilities for how to apply |
176 following proof, there are two possibilities for how to apply |
153 @{ML foo_tac'}. |
177 @{ML foo_tac'}. |
156 lemma "\<lbrakk>P \<or> Q; P \<or> Q\<rbrakk> \<Longrightarrow> Q \<or> P" |
180 lemma "\<lbrakk>P \<or> Q; P \<or> Q\<rbrakk> \<Longrightarrow> Q \<or> P" |
157 apply(tactic {* foo_tac' 1 *}) |
181 apply(tactic {* foo_tac' 1 *}) |
158 back |
182 back |
159 done |
183 done |
160 |
184 |
|
185 |
161 text {* |
186 text {* |
162 By using \isacommand{back}, we construct the proof that uses the |
187 By using \isacommand{back}, we construct the proof that uses the |
163 second assumption to complete the proof. In more interesting |
188 second assumption. In more interesting situations, different possibilities |
164 situations, different possibilities can lead to different proofs. |
189 can lead to different proofs and even often need to be explored when |
|
190 a first proof attempt is unsuccessful. |
165 |
191 |
166 \begin{readmore} |
192 \begin{readmore} |
167 See @{ML_file "Pure/General/seq.ML"} for the implementation of lazy |
193 See @{ML_file "Pure/General/seq.ML"} for the implementation of lazy |
168 sequences. However in day-to-day Isabelle programming, one rarely |
194 sequences. However in day-to-day Isabelle programming, one rarely |
169 constructs sequences explicitly, but uses the predefined functions |
195 constructs sequences explicitly, but uses the predefined functions |
170 instead. |
196 instead. |
171 \end{readmore} |
197 \end{readmore} |
172 |
198 |
173 *} |
199 For a beginner it might be surprising that tactics, which transform |
174 |
200 one proof state to the next, are functions from theorems to theorem |
175 section {* Basic Tactics *} |
201 (sequences). The surprise resolves by knowing that every |
|
202 proof state is indeed a theorem. To shed more light on this, |
|
203 let us modify the code of @{ML all_tac} to obtain the following |
|
204 tactic |
|
205 *} |
|
206 |
|
207 ML{*fun my_print_tac ctxt thm = |
|
208 let |
|
209 val _ = warning (str_of_thm ctxt thm) |
|
210 in |
|
211 Seq.single thm |
|
212 end*} |
|
213 |
|
214 text {* |
|
215 which prints out the given theorem (using the string-function defined |
|
216 in Section~\ref{sec:printing}) and then behaves like @{ML all_tac}. We |
|
217 now can inspect every proof state in the follwing proof. On the left-hand |
|
218 side we show the goal state as shown by the system; on the right-hand |
|
219 side the print out from our @{ML my_print_tac}. |
|
220 *} |
|
221 |
|
222 lemma shows "\<lbrakk>A; B\<rbrakk> \<Longrightarrow> A \<and> B" |
|
223 apply(tactic {* my_print_tac @{context} *}) |
|
224 |
|
225 txt{* \small |
|
226 \begin{tabular}{@ {}l@ {}p{0.7\textwidth}@ {}} |
|
227 \begin{minipage}[t]{0.3\textwidth} |
|
228 @{subgoals [display]} |
|
229 \end{minipage} & |
|
230 \hfill@{text "(\<lbrakk>A; B\<rbrakk> \<Longrightarrow> A \<and> B) \<Longrightarrow> (\<lbrakk>A; B\<rbrakk> \<Longrightarrow> A \<and> B)"} |
|
231 \end{tabular} |
|
232 *} |
|
233 |
|
234 apply(rule conjI) |
|
235 apply(tactic {* my_print_tac @{context} *}) |
|
236 |
|
237 txt{* \small |
|
238 \begin{tabular}{@ {}l@ {}p{0.76\textwidth}@ {}} |
|
239 \begin{minipage}[t]{0.26\textwidth} |
|
240 @{subgoals [display]} |
|
241 \end{minipage} & |
|
242 \hfill@{text "(\<lbrakk>A; B\<rbrakk> \<Longrightarrow> A) \<Longrightarrow> (\<lbrakk>A; B\<rbrakk> \<Longrightarrow> B) \<Longrightarrow> (\<lbrakk>A; B\<rbrakk> \<Longrightarrow> A \<and> B)"} |
|
243 \end{tabular} |
|
244 *} |
|
245 |
|
246 apply(assumption) |
|
247 apply(tactic {* my_print_tac @{context} *}) |
|
248 |
|
249 txt{* \small |
|
250 \begin{tabular}{@ {}l@ {}p{0.7\textwidth}@ {}} |
|
251 \begin{minipage}[t]{0.3\textwidth} |
|
252 @{subgoals [display]} |
|
253 \end{minipage} & |
|
254 \hfill@{text "(\<lbrakk>A; B\<rbrakk> \<Longrightarrow> B) \<Longrightarrow> (\<lbrakk>A; B\<rbrakk> \<Longrightarrow> A \<and> B)"} |
|
255 \end{tabular} |
|
256 *} |
|
257 |
|
258 apply(assumption) |
|
259 apply(tactic {* my_print_tac @{context} *}) |
|
260 |
|
261 txt{* \small |
|
262 \begin{tabular}{@ {}l@ {}p{0.7\textwidth}@ {}} |
|
263 \begin{minipage}[t]{0.3\textwidth} |
|
264 @{subgoals [display]} |
|
265 \end{minipage} & |
|
266 \hfill@{text "\<lbrakk>A; B\<rbrakk> \<Longrightarrow> A \<and> B"} |
|
267 \end{tabular} |
|
268 *} |
|
269 |
|
270 done |
|
271 |
|
272 text {* |
|
273 As can be seen, internally every goal state is an implication of the form |
|
274 |
|
275 @{text[display] "A\<^isub>1 \<Longrightarrow> \<dots> \<Longrightarrow> A\<^isub>n \<Longrightarrow> (C)"} |
|
276 |
|
277 where @{term C} is the goal to be proved and the @{term "A\<^isub>i"} are the |
|
278 subgoals. Since the goal @{term C} can potentially be an implication, |
|
279 there is a protector (invisible in the print out above) wrapped around |
|
280 it. This prevents that premises are misinterpreted as open subgoals. |
|
281 While tactics can operate on the subgoals (the @{text "A\<^isub>i"} above), they |
|
282 are expected to leave the conclusion @{term C} intact, with the |
|
283 exception of possibly instantiating schematic variables. |
|
284 |
|
285 *} |
|
286 |
|
287 section {* Simple Tactics *} |
176 |
288 |
177 text {* |
289 text {* |
178 As seen above, the function @{ML atac} corresponds to the assumption tactic. |
290 As seen above, the function @{ML atac} corresponds to the assumption tactic. |
179 *} |
291 *} |
180 |
292 |
182 apply(tactic {* atac 1 *}) |
294 apply(tactic {* atac 1 *}) |
183 done |
295 done |
184 |
296 |
185 text {* |
297 text {* |
186 Similarly, @{ML rtac}, @{ML dtac}, @{ML etac} and @{ML ftac} correspond |
298 Similarly, @{ML rtac}, @{ML dtac}, @{ML etac} and @{ML ftac} correspond |
187 to @{ML_text rule}, @{ML_text drule}, @{ML_text erule} and @{ML_text frule}, |
299 to @{text rule}, @{text drule}, @{text erule} and @{text frule}, |
188 respectively. Below are three examples with the resulting goal state. How |
300 respectively. Below are three examples with the resulting goal state. How |
189 they work should therefore be self-explanatory. |
301 they work should therefore be self-explanatory. |
190 *} |
302 *} |
191 |
303 |
192 lemma shows "P \<and> Q" |
304 lemma shows "P \<and> Q" |
301 txt {* |
413 txt {* |
302 which yields the printout: |
414 which yields the printout: |
303 |
415 |
304 \begin{quote}\small |
416 \begin{quote}\small |
305 \begin{tabular}{ll} |
417 \begin{tabular}{ll} |
306 params: & @{term x}, @{term y}\\ |
418 params: & @{term x}, @{term y}\\ |
307 schematics: & @{term z}\\ |
419 schematics: & @{term z}\\ |
308 asms: & @{term "A x y"}\\ |
420 assumptions: & @{term "A x y"}\\ |
309 concl: & @{term "B y x \<longrightarrow> C (z y) x"}\\ |
421 conclusion: & @{term "B y x \<longrightarrow> C (z y) x"}\\ |
310 prems: & @{term "A x y"} |
422 premises: & @{term "A x y"} |
311 \end{tabular} |
423 \end{tabular} |
312 \end{quote} |
424 \end{quote} |
313 |
425 |
314 Note in the actual output the brown colour of the variables @{term x} and |
426 Note in the actual output the brown colour of the variables @{term x} and |
315 @{term y}. Although parameters in the original goal, they are fixed inside |
427 @{term y}. Although parameters in the original goal, they are fixed inside |
424 @{ML rewrite_goals_tac} |
536 @{ML rewrite_goals_tac} |
425 @{ML cut_facts_tac} |
537 @{ML cut_facts_tac} |
426 @{ML ObjectLogic.full_atomize_tac} |
538 @{ML ObjectLogic.full_atomize_tac} |
427 @{ML ObjectLogic.rulify_tac} |
539 @{ML ObjectLogic.rulify_tac} |
428 @{ML resolve_tac} |
540 @{ML resolve_tac} |
429 *} |
|
430 |
|
431 |
|
432 |
|
433 text {* |
|
434 |
|
435 |
|
436 A goal (or goal state) is a special @{ML_type thm}, which by |
|
437 convention is an implication of the form: |
|
438 |
|
439 @{text[display] "A\<^isub>1 \<Longrightarrow> \<dots> \<Longrightarrow> A\<^isub>n \<Longrightarrow> #(C)"} |
|
440 |
|
441 where @{term C} is the goal to be proved and the @{term "A\<^isub>i"} are the open |
|
442 subgoals. |
|
443 Since the goal @{term C} can potentially be an implication, there is a |
|
444 @{text "#"} wrapped around it, which prevents that premises are |
|
445 misinterpreted as open subgoals. The wrapper @{text "# :: prop \<Rightarrow> |
|
446 prop"} is just the identity function and used as a syntactic marker. |
|
447 |
|
448 |
|
449 |
|
450 |
|
451 |
|
452 While tactics can operate on the subgoals (the @{text "A\<^isub>i"} above), they |
|
453 are expected to leave the conclusion @{term C} intact, with the |
|
454 exception of possibly instantiating schematic variables. |
|
455 |
|
456 |
|
457 |
|
458 *} |
541 *} |
459 |
542 |
460 section {* Structured Proofs *} |
543 section {* Structured Proofs *} |
461 |
544 |
462 lemma True |
545 lemma True |