48 THEN rtac @{thm disjI1} 1 |
47 THEN rtac @{thm disjI1} 1 |
49 THEN atac 1) |
48 THEN atac 1) |
50 end" "?P \<or> ?Q \<Longrightarrow> ?Q \<or> ?P"} |
49 end" "?P \<or> ?Q \<Longrightarrow> ?Q \<or> ?P"} |
51 |
50 |
52 To start the proof, the function @{ML "Goal.prove"}~@{text "ctxt xs As C |
51 To start the proof, the function @{ML "Goal.prove"}~@{text "ctxt xs As C |
53 tac"} sets up a goal state for proving the goal @{text C} under the |
52 tac"} sets up a goal state for proving the goal @{text C} |
54 assumptions @{text As} (empty in the proof at hand) with the variables |
53 (that is @{prop "P \<or> Q \<Longrightarrow> Q \<or> P"} in the proof at hand) under the |
|
54 assumptions @{text As} (happens to be empty) with the variables |
55 @{text xs} that will be generalised once the goal is proved (in our case |
55 @{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; |
56 @{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). |
57 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 |
58 The functions @{ML etac}, @{ML rtac} and @{ML atac} correspond to |
59 @{text erule}, @{text rule} and @{text assumption}, respectively. |
59 @{text erule}, @{text rule} and @{text assumption}, respectively. |
60 The operator @{ML THEN} strings tactics together. |
60 The operator @{ML THEN} strings the tactics together. |
61 |
61 |
62 \begin{readmore} |
62 \begin{readmore} |
63 To learn more about the function @{ML Goal.prove} see \isccite{sec:results} and |
63 To learn more about the function @{ML Goal.prove} see \isccite{sec:results} |
64 the file @{ML_file "Pure/goal.ML"}. For more information about the internals of goals see |
64 and the file @{ML_file "Pure/goal.ML"}. For more information about the |
65 \isccite{sec:tactical-goals}. |
65 internals of goals see \isccite{sec:tactical-goals}. See @{ML_file |
|
66 "Pure/tactic.ML"} and @{ML_file "Pure/tctical.ML"} for the code of basic |
|
67 tactics and tactic combinators; see also Chapters 3 and 4 in the old |
|
68 Isabelle Reference Manual. |
66 \end{readmore} |
69 \end{readmore} |
67 |
70 |
68 Note that we used antiquotations for referencing the theorems. We could also |
71 Note that we used antiquotations for referencing the theorems. We could also |
69 just have written @{ML "etac disjE 1"} and so on, but this is considered bad |
72 just have written @{ML "etac disjE 1"} and so on, but this is considered bad |
70 style. The reason is that the binding for @{ML disjE} can be re-assigned by |
73 style. The reason is that the binding for @{ML disjE} can be re-assigned by |
109 THEN' rtac @{thm disjI1} |
112 THEN' rtac @{thm disjI1} |
110 THEN' atac)*} |
113 THEN' atac)*} |
111 |
114 |
112 text {* |
115 text {* |
113 and then give the number for the subgoal explicitly when the tactic is |
116 and then give the number for the subgoal explicitly when the tactic is |
114 called. So in the next proof we discharge first the second subgoal, |
117 called. For every operator that combines tactics, such a primed version |
|
118 exists. So in the next proof we can first discharge the second subgoal, |
115 and after that the first. |
119 and after that the first. |
116 *} |
120 *} |
117 |
121 |
118 lemma "P1 \<or> Q1 \<Longrightarrow> Q1 \<or> P1" |
122 lemma "P1 \<or> Q1 \<Longrightarrow> Q1 \<or> P1" |
119 and "P2 \<or> Q2 \<Longrightarrow> Q2 \<or> P2" |
123 and "P2 \<or> Q2 \<Longrightarrow> Q2 \<or> P2" |
120 apply(tactic {* foo_tac' 2 *}) |
124 apply(tactic {* foo_tac' 2 *}) |
121 apply(tactic {* foo_tac' 1 *}) |
125 apply(tactic {* foo_tac' 1 *}) |
122 done |
126 done |
123 |
127 |
124 text {* |
128 text {* |
125 The tactic @{ML foo_tac} is very specific for analysing goals of the form |
129 (FIXME: maybe add something about how each goal state is interpreted |
126 @{prop "P \<or> Q \<Longrightarrow> Q \<or> P"}. If the goal is not of this form, then @{ML foo_tac} |
130 as a theorem) |
127 throws the error message about an empty result sequence---meaning the tactic |
131 |
128 failed. The reason for this message is that tactics are functions that map |
132 The tactic @{ML foo_tac} (and @{ML foo_tac'}) are very specific for |
129 a goal state to a (lazy) sequence of successor states, hence the type of a |
133 analysing goals only of the form @{prop "P \<or> Q \<Longrightarrow> Q \<or> P"}. If the goal is not |
130 tactic is |
134 of this form, then @{ML foo_tac} throws the error message: |
|
135 |
|
136 \begin{isabelle} |
|
137 @{text "*** empty result sequence -- proof command failed"}\\ |
|
138 @{text "*** At command \"apply\"."} |
|
139 \end{isabelle} |
|
140 |
|
141 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, |
|
143 hence the type of a tactic is |
131 |
144 |
132 @{text [display, gray] "type tactic = thm -> thm Seq.seq"} |
145 @{text [display, gray] "type tactic = thm -> thm Seq.seq"} |
133 |
146 |
134 Consequently, if a tactic fails, then it returns the empty sequence. This |
147 It is custom that if a tactic fails, it should return the empty sequence: |
135 is by the way the default behaviour for a failing tactic; tactics should |
148 tactics should not raise exceptions willy-nilly. |
136 not raise exceptions. |
149 |
137 |
150 The lazy list of possible successor states shows through to the user-level |
138 In the following example there are two possibilities for how to apply the tactic. |
151 of Isabelle when using the command \isacommand{back}. For instance in the |
|
152 following proof, there are two possibilities for how to apply |
|
153 @{ML foo_tac'}. |
139 *} |
154 *} |
140 |
155 |
141 lemma "\<lbrakk>P \<or> Q; P \<or> Q\<rbrakk> \<Longrightarrow> Q \<or> P" |
156 lemma "\<lbrakk>P \<or> Q; P \<or> Q\<rbrakk> \<Longrightarrow> Q \<or> P" |
142 apply(tactic {* foo_tac' 1 *}) |
157 apply(tactic {* foo_tac' 1 *}) |
143 back |
158 back |
144 done |
159 done |
145 |
160 |
146 text {* |
161 text {* |
147 The application of the tactic results in a sequence of two possible |
162 By using \isacommand{back}, we construct the proof that uses the |
148 proofs. The Isabelle command \isacommand{back} allows us to explore both |
163 second assumption to complete the proof. In more interesting |
149 possibilities. |
164 situations, different possibilities can lead to different proofs. |
150 |
165 |
151 \begin{readmore} |
166 \begin{readmore} |
152 See @{ML_file "Pure/General/seq.ML"} for the implementation of lazy |
167 See @{ML_file "Pure/General/seq.ML"} for the implementation of lazy |
153 sequences. However in day-to-day Isabelle programming, one rarely |
168 sequences. However in day-to-day Isabelle programming, one rarely |
154 constructs sequences explicitly, but uses the predefined functions |
169 constructs sequences explicitly, but uses the predefined functions |
155 instead. See @{ML_file "Pure/tactic.ML"} and |
170 instead. |
156 @{ML_file "Pure/tctical.ML"} for the code of basic tactics and tactic |
|
157 combinators; see also Chapters 3 and 4 in |
|
158 the old Isabelle Reference Manual. |
|
159 \end{readmore} |
171 \end{readmore} |
160 |
172 |
161 *} |
173 *} |
162 |
174 |
163 |
|
164 section {* Basic Tactics *} |
175 section {* Basic Tactics *} |
165 |
176 |
166 lemma shows "False \<Longrightarrow> False" |
177 text {* |
|
178 As seen above, the function @{ML atac} corresponds to the assumption tactic. |
|
179 *} |
|
180 |
|
181 lemma shows "P \<Longrightarrow> P" |
167 apply(tactic {* atac 1 *}) |
182 apply(tactic {* atac 1 *}) |
168 done |
183 done |
169 |
184 |
170 lemma shows "True \<and> True" |
185 text {* |
|
186 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}, |
|
188 respectively. Below are three examples with the resulting goal state. How |
|
189 they work should therefore be self-explanatory. |
|
190 *} |
|
191 |
|
192 lemma shows "P \<and> Q" |
171 apply(tactic {* rtac @{thm conjI} 1 *}) |
193 apply(tactic {* rtac @{thm conjI} 1 *}) |
172 txt {* @{subgoals [display]} *} |
194 txt{*@{subgoals [display]}*} |
173 (*<*)oops(*>*) |
195 (*<*)oops(*>*) |
174 |
196 |
175 lemma |
197 lemma shows "P \<and> Q \<Longrightarrow> False" |
176 shows "Foo" |
|
177 and "True \<and> True" |
|
178 apply(tactic {* rtac @{thm conjI} 2 *}) |
|
179 txt {* @{subgoals [display]} *} |
|
180 (*<*)oops(*>*) |
|
181 |
|
182 lemma shows "False \<and> False \<Longrightarrow> False" |
|
183 apply(tactic {* etac @{thm conjE} 1 *}) |
198 apply(tactic {* etac @{thm conjE} 1 *}) |
184 txt {* @{subgoals [display]} *} |
199 txt{*@{subgoals [display]}*} |
185 (*<*)oops(*>*) |
200 (*<*)oops(*>*) |
186 |
201 |
187 lemma shows "False \<and> True \<Longrightarrow> False" |
202 lemma shows "False \<and> True \<Longrightarrow> False" |
188 apply(tactic {* dtac @{thm conjunct2} 1 *}) |
203 apply(tactic {* dtac @{thm conjunct2} 1 *}) |
189 txt {* @{subgoals [display]} *} |
204 txt{*@{subgoals [display]}*} |
190 (*<*)oops(*>*) |
205 (*<*)oops(*>*) |
191 |
206 |
192 text {* |
207 text {* |
193 similarly @{ML ftac} |
208 As mentioned above, most basic tactics take a number as argument, which |
194 *} |
209 addresses to subgoal they are analysing. |
195 |
210 *} |
196 text {* diagnostics *} |
211 |
197 lemma shows "True \<Longrightarrow> False" |
212 lemma shows "Foo" and "P \<and> Q" |
|
213 apply(tactic {* rtac @{thm conjI} 2 *}) |
|
214 txt {*@{subgoals [display]}*} |
|
215 (*<*)oops(*>*) |
|
216 |
|
217 text {* |
|
218 Corresponding to @{ML rtac}, there is also the tactic @{ML resolve_tac}, which |
|
219 however expects a list of theorems as arguments. From this list it will apply with |
|
220 the first applicable theorem (later theorems that are also applicable can be |
|
221 explored via the lazy sequences mechanism). Given the abbreviation |
|
222 *} |
|
223 |
|
224 ML{*val resolve_tac_xmp = resolve_tac [@{thm impI}, @{thm conjI}]*} |
|
225 |
|
226 text {* |
|
227 an example for @{ML resolve_tac} is the following proof where first an outermost |
|
228 implication is analysed and then an outermost conjunction. |
|
229 *} |
|
230 |
|
231 lemma shows "C \<longrightarrow> (A \<and> B)" and "(A \<longrightarrow> B) \<and> C" |
|
232 apply(tactic {* resolve_tac_xmp 1 *}) |
|
233 apply(tactic {* resolve_tac_xmp 2 *}) |
|
234 txt{* @{subgoals [display]} *} |
|
235 (*<*)oops(*>*) |
|
236 |
|
237 text {* |
|
238 Similarly versions exists for @{ML atac} (@{ML assume_tac}), @{ML etac} |
|
239 (@{ML eresolve_tac}) and so on. |
|
240 |
|
241 The tactic @{ML print_tac} is useful for low-level debugging of tactics: it |
|
242 prints out a message and the current goal state. |
|
243 *} |
|
244 |
|
245 lemma shows "False \<Longrightarrow> True" |
198 apply(tactic {* print_tac "foo message" *}) |
246 apply(tactic {* print_tac "foo message" *}) |
199 (*<*)oops(*>*) |
247 (*<*)oops(*>*) |
200 |
248 |
201 text {* Let us assume the following four string conversion functions: *} |
249 text {* |
202 |
250 Also for useful for debugging, but not exclusively, are the tactics @{ML all_tac} and |
203 ML{*fun str_of_cterm ctxt t = |
251 @{ML no_tac}. The former always succeeds (but does not change the goal state), and |
204 Syntax.string_of_term ctxt (term_of t) |
252 the latter always fails. |
205 |
253 |
206 fun str_of_cterms ctxt ts = |
254 (FIXME explain RS MRS) |
207 commas (map (str_of_cterm ctxt) ts) |
255 |
208 |
256 Often proofs involve elaborate operations on assumptions and variables |
209 fun str_of_thm ctxt thm = |
257 @{text "\<And>"}-quantified in the goal state. To do such operations on the ML-level |
210 let |
258 using the basic tactics, is very unwieldy and brittle. Some convenience and |
211 val {prop, ...} = crep_thm thm |
259 safety is provided by the tactic @{ML SUBPROOF}. This tactic fixes the parameters |
212 in |
260 and binds the various components of a proof state into a record. |
213 str_of_cterm ctxt prop |
261 *} |
214 end |
262 |
215 |
263 text_raw{* |
216 fun str_of_thms ctxt thms = |
264 \begin{figure} |
217 commas (map (str_of_thm ctxt) thms)*} |
265 \begin{isabelle} |
218 |
266 *} |
219 text {* |
|
220 and the following function |
|
221 *} |
|
222 |
|
223 ML{*fun sp_tac {prems, params, asms, concl, context, schematics} = |
267 ML{*fun sp_tac {prems, params, asms, concl, context, schematics} = |
224 let |
268 let |
225 val str_of_params = str_of_cterms context params |
269 val str_of_params = str_of_cterms context params |
226 val str_of_asms = str_of_cterms context asms |
270 val str_of_asms = str_of_cterms context asms |
227 val str_of_concl = str_of_cterm context concl |
271 val str_of_concl = str_of_cterm context concl |
234 warning ("concl: " ^ str_of_concl); |
278 warning ("concl: " ^ str_of_concl); |
235 warning ("prems: " ^ str_of_prems)) |
279 warning ("prems: " ^ str_of_prems)) |
236 in |
280 in |
237 no_tac |
281 no_tac |
238 end*} |
282 end*} |
239 |
283 text_raw{* |
240 text {* |
284 \end{isabelle} |
241 then the tactic @{ML SUBPROOF} fixes the parameters and binds the various components |
285 \caption{A function that prints out the various parameters provided by the tactic |
242 of a proof state into a record. For example |
286 @{ML SUBPROOF}. It uses the functions extracting strings from @{ML_type cterm}s |
243 *} |
287 and @{ML_type thm}s, which are defined in Section~\ref{sec:printing}.\label{fig:sptac}} |
244 |
288 \end{figure} |
245 lemma |
289 *} |
246 shows "\<And>x y. A x y \<Longrightarrow> B y x \<longrightarrow> C (?z y) x" |
290 |
|
291 text {* |
|
292 To see what happens, assume the function defined in Figure~\ref{fig:sptac}, which |
|
293 takes a record as argument and just prints out the content of this record (using the |
|
294 string transformation functions defined in Section~\ref{sec:printing}). Consider |
|
295 now the proof |
|
296 *} |
|
297 |
|
298 lemma shows "\<And>x y. A x y \<Longrightarrow> B y x \<longrightarrow> C (?z y) x" |
247 apply(tactic {* SUBPROOF sp_tac @{context} 1 *})? |
299 apply(tactic {* SUBPROOF sp_tac @{context} 1 *})? |
248 |
300 |
249 txt {* |
301 txt {* |
250 prints out |
302 which yields the printout: |
251 |
303 |
252 \begin{center} |
304 \begin{quote}\small |
253 \begin{tabular}{ll} |
305 \begin{tabular}{ll} |
254 params: & @{term x}, @{term y}\\ |
306 params: & @{term x}, @{term y}\\ |
255 schematics: & @{term z}\\ |
307 schematics: & @{term z}\\ |
256 asms: & @{term "A x y"}\\ |
308 asms: & @{term "A x y"}\\ |
257 concl: & @{term "B y x \<longrightarrow> C (z y) x"}\\ |
309 concl: & @{term "B y x \<longrightarrow> C (z y) x"}\\ |
258 prems: & @{term "A x y"} |
310 prems: & @{term "A x y"} |
259 \end{tabular} |
311 \end{tabular} |
260 \end{center} |
312 \end{quote} |
261 |
313 |
262 Continuing the proof script with |
314 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 |
|
316 the subproof. Similarly the schematic variable @{term z}. The assumption |
|
317 is bound once as @{ML_type cterm} to the record-variable @{text asms} and |
|
318 another time as @{ML_type thm} to @{text prems}. |
|
319 |
|
320 Notice also that we had to append @{text "?"} to \isacommand{apply}. The |
|
321 reason is that @{ML SUBPROOF} normally expects that the subgoal is solved completely. |
|
322 Since in the function @{ML sp_tac} we returned the tactic @{ML no_tac}, the subproof |
|
323 obviously fails. The question-mark allows us to recover from this failure |
|
324 in a graceful manner so that the warning messages are not overwritten |
|
325 by the error message. |
|
326 |
|
327 If we continue the proof script by applying the @{text impI}-rule |
263 *} |
328 *} |
264 |
329 |
265 apply(rule impI) |
330 apply(rule impI) |
266 apply(tactic {* SUBPROOF sp_tac @{context} 1 *})? |
331 apply(tactic {* SUBPROOF sp_tac @{context} 1 *})? |
267 |
332 |
268 txt {* |
333 txt {* |
269 prints out |
334 then @{ML SUBPROOF} prints out |
270 |
335 |
271 \begin{center} |
336 \begin{quote}\small |
272 \begin{tabular}{ll} |
337 \begin{tabular}{ll} |
273 params: & @{term x}, @{term y}\\ |
338 params: & @{term x}, @{term y}\\ |
274 schematics: & @{term z}\\ |
339 schematics: & @{term z}\\ |
275 asms: & @{term "A x y"}, @{term "B y x"}\\ |
340 asms: & @{term "A x y"}, @{term "B y x"}\\ |
276 concl: & @{term "C (z y) x"}\\ |
341 concl: & @{term "C (z y) x"}\\ |
277 prems: & @{term "A x y"}, @{term "B y x"} |
342 prems: & @{term "A x y"}, @{term "B y x"} |
278 \end{tabular} |
343 \end{tabular} |
279 \end{center} |
344 \end{quote} |
280 *} |
345 *} |
281 (*<*)oops(*>*) |
346 (*<*)oops(*>*) |
282 |
347 |
283 |
348 text {* |
284 text {* |
349 where we now also have @{term "B y x"} as assumption. |
285 @{ML PRIMITIVE}? @{ML SUBGOAL} see page 32 in ref |
350 |
286 *} |
351 One convenience of @{ML SUBPROOF} is that we can apply assumption |
287 |
352 using the usual tactics, because the parameter @{text prems} |
288 text {* |
353 contains the assumptions as theorems. With this we can easily |
289 @{ML all_tac} @{ML no_tac} |
354 implement a tactic that almost behaves like @{ML atac}: |
290 *} |
355 *} |
|
356 |
|
357 lemma shows "\<And>x y. \<lbrakk>B x y; A x y; C x y\<rbrakk> \<Longrightarrow> A x y" |
|
358 apply(tactic |
|
359 {* SUBPROOF (fn {prems, ...} => resolve_tac prems 1) @{context} 1 *}) |
|
360 txt{* yields |
|
361 @{subgoals [display]} *} |
|
362 (*<*)oops(*>*) |
|
363 |
|
364 |
|
365 text {* |
|
366 The restriction in this tactic is that it cannot instantiate any |
|
367 schematic variables. This might be seen as a defect, but is actually |
|
368 an advantage in the situations for which @{ML SUBPROOF} was designed: |
|
369 the reason is that instantiation of schematic variables can potentially |
|
370 has affect several goals and can render them unprovable. |
|
371 |
|
372 A similar but less powerful function is @{ML SUBGOAL}. It allows you to |
|
373 inspect a subgoal specified by a number. |
|
374 *} |
|
375 |
|
376 ML %linenumbers{*fun select_tac (t,i) = |
|
377 case t of |
|
378 @{term "Trueprop"} $ t' => select_tac (t',i) |
|
379 | @{term "op \<and>"} $ _ $ _ => rtac @{thm conjI} i |
|
380 | @{term "op \<longrightarrow>"} $ _ $ _ => rtac @{thm impI} i |
|
381 | @{term "Not"} $ _ => rtac @{thm notI} i |
|
382 | Const (@{const_name "All"}, _) $ _ => rtac @{thm allI} i |
|
383 | _ => no_tac*} |
|
384 |
|
385 lemma shows "A \<and> B" "A \<longrightarrow> B" "\<forall>x. C x" |
|
386 apply(tactic {* SUBGOAL select_tac 1 *}) |
|
387 apply(tactic {* SUBGOAL select_tac 3 *}) |
|
388 apply(tactic {* SUBGOAL select_tac 4 *}) |
|
389 txt{* @{subgoals [display]} *} |
|
390 (*<*)oops(*>*) |
|
391 |
|
392 text {* |
|
393 However, this example is contrived, as there are much simpler ways |
|
394 to implement a proof procedure like the one above. They will be explained |
|
395 in the next section. |
|
396 |
|
397 A variant of @{ML SUBGOAL} is @{ML CSUBGOAL} which allows access to the goal |
|
398 as @{ML_type cterm} instead of a @{ML_type term}. |
|
399 *} |
|
400 |
291 |
401 |
292 section {* Operations on Tactics *} |
402 section {* Operations on Tactics *} |
293 |
403 |
294 text {* THEN *} |
404 text {* @{ML THEN} *} |
295 |
405 |
296 lemma shows "(True \<and> True) \<and> False" |
406 lemma shows "(Foo \<and> Bar) \<and> False" |
297 apply(tactic {* (rtac @{thm conjI} 1) THEN (rtac @{thm conjI} 1) *}) |
407 apply(tactic {* (rtac @{thm conjI} 1) |
|
408 THEN (rtac @{thm conjI} 1) *}) |
298 txt {* @{subgoals [display]} *} |
409 txt {* @{subgoals [display]} *} |
299 (*<*)oops(*>*) |
410 (*<*)oops(*>*) |
300 |
411 |
301 lemma shows "True \<and> False" |
412 ML{*val orelse_xmp = (rtac @{thm disjI1} ORELSE' rtac @{thm conjI})*} |
302 apply(tactic {* (rtac @{thm disjI1} 1) ORELSE (rtac @{thm conjI} 1) *}) |
413 |
|
414 lemma shows "True \<and> False" and "Foo \<or> Bar" |
|
415 apply(tactic {* orelse_xmp 1 *}) |
|
416 apply(tactic {* orelse_xmp 3 *}) |
303 txt {* @{subgoals [display]} *} |
417 txt {* @{subgoals [display]} *} |
304 (*<*)oops(*>*) |
418 (*<*)oops(*>*) |
305 |
419 |
306 |
420 |
307 text {* |
421 text {* |
308 @{ML EVERY} @{ML REPEAT} |
422 @{ML EVERY} @{ML REPEAT} @{ML DETERM} |
309 |
423 |
310 @{ML rewrite_goals_tac} |
424 @{ML rewrite_goals_tac} |
311 @{ML cut_facts_tac} |
425 @{ML cut_facts_tac} |
312 @{ML ObjectLogic.full_atomize_tac} |
426 @{ML ObjectLogic.full_atomize_tac} |
313 @{ML ObjectLogic.rulify_tac} |
427 @{ML ObjectLogic.rulify_tac} |