1 theory Tactic |
|
2 imports Base |
|
3 begin |
|
4 |
|
5 chapter {* Tactical reasoning *} |
|
6 |
|
7 text {* Tactical reasoning works by refining an initial claim in a |
|
8 backwards fashion, until a solved form is reached. A @{text "goal"} |
|
9 consists of several subgoals that need to be solved in order to |
|
10 achieve the main statement; zero subgoals means that the proof may |
|
11 be finished. A @{text "tactic"} is a refinement operation that maps |
|
12 a goal to a lazy sequence of potential successors. A @{text |
|
13 "tactical"} is a combinator for composing tactics. *} |
|
14 |
|
15 |
|
16 section {* Goals \label{sec:tactical-goals} *} |
|
17 |
|
18 text {* |
|
19 Isabelle/Pure represents a goal as a theorem stating that the |
|
20 subgoals imply the main goal: @{text "A\<^sub>1 \<Longrightarrow> \<dots> \<Longrightarrow> A\<^sub>n \<Longrightarrow> |
|
21 C"}. The outermost goal structure is that of a Horn Clause: i.e.\ |
|
22 an iterated implication without any quantifiers\footnote{Recall that |
|
23 outermost @{text "\<And>x. \<phi>[x]"} is always represented via schematic |
|
24 variables in the body: @{text "\<phi>[?x]"}. These variables may get |
|
25 instantiated during the course of reasoning.}. For @{text "n = 0"} |
|
26 a goal is called ``solved''. |
|
27 |
|
28 The structure of each subgoal @{text "A\<^sub>i"} is that of a |
|
29 general Hereditary Harrop Formula @{text "\<And>x\<^sub>1 \<dots> |
|
30 \<And>x\<^sub>k. H\<^sub>1 \<Longrightarrow> \<dots> \<Longrightarrow> H\<^sub>m \<Longrightarrow> B"}. Here @{text |
|
31 "x\<^sub>1, \<dots>, x\<^sub>k"} are goal parameters, i.e.\ |
|
32 arbitrary-but-fixed entities of certain types, and @{text |
|
33 "H\<^sub>1, \<dots>, H\<^sub>m"} are goal hypotheses, i.e.\ facts that may |
|
34 be assumed locally. Together, this forms the goal context of the |
|
35 conclusion @{text B} to be established. The goal hypotheses may be |
|
36 again arbitrary Hereditary Harrop Formulas, although the level of |
|
37 nesting rarely exceeds 1--2 in practice. |
|
38 |
|
39 The main conclusion @{text C} is internally marked as a protected |
|
40 proposition, which is represented explicitly by the notation @{text |
|
41 "#C"} here. This ensures that the decomposition into subgoals and |
|
42 main conclusion is well-defined for arbitrarily structured claims. |
|
43 |
|
44 \medskip Basic goal management is performed via the following |
|
45 Isabelle/Pure rules: |
|
46 |
|
47 \[ |
|
48 \infer[@{text "(init)"}]{@{text "C \<Longrightarrow> #C"}}{} \qquad |
|
49 \infer[@{text "(finish)"}]{@{text "C"}}{@{text "#C"}} |
|
50 \] |
|
51 |
|
52 \medskip The following low-level variants admit general reasoning |
|
53 with protected propositions: |
|
54 |
|
55 \[ |
|
56 \infer[@{text "(protect)"}]{@{text "#C"}}{@{text "C"}} \qquad |
|
57 \infer[@{text "(conclude)"}]{@{text "A\<^sub>1 \<Longrightarrow> \<dots> \<Longrightarrow> A\<^sub>n \<Longrightarrow> C"}}{@{text "A\<^sub>1 \<Longrightarrow> \<dots> \<Longrightarrow> A\<^sub>n \<Longrightarrow> #C"}} |
|
58 \] |
|
59 *} |
|
60 |
|
61 text %mlref {* |
|
62 \begin{mldecls} |
|
63 @{index_ML Goal.init: "cterm -> thm"} \\ |
|
64 @{index_ML Goal.finish: "Proof.context -> thm -> thm"} \\ |
|
65 @{index_ML Goal.protect: "thm -> thm"} \\ |
|
66 @{index_ML Goal.conclude: "thm -> thm"} \\ |
|
67 \end{mldecls} |
|
68 |
|
69 \begin{description} |
|
70 |
|
71 \item @{ML "Goal.init"}~@{text C} initializes a tactical goal from |
|
72 the well-formed proposition @{text C}. |
|
73 |
|
74 \item @{ML "Goal.finish"}~@{text "ctxt thm"} checks whether theorem |
|
75 @{text "thm"} is a solved goal (no subgoals), and concludes the |
|
76 result by removing the goal protection. The context is only |
|
77 required for printing error messages. |
|
78 |
|
79 \item @{ML "Goal.protect"}~@{text "thm"} protects the full statement |
|
80 of theorem @{text "thm"}. |
|
81 |
|
82 \item @{ML "Goal.conclude"}~@{text "thm"} removes the goal |
|
83 protection, even if there are pending subgoals. |
|
84 |
|
85 \end{description} |
|
86 *} |
|
87 |
|
88 |
|
89 section {* Tactics\label{sec:tactics} *} |
|
90 |
|
91 text {* A @{text "tactic"} is a function @{text "goal \<rightarrow> goal\<^sup>*\<^sup>*"} that |
|
92 maps a given goal state (represented as a theorem, cf.\ |
|
93 \secref{sec:tactical-goals}) to a lazy sequence of potential |
|
94 successor states. The underlying sequence implementation is lazy |
|
95 both in head and tail, and is purely functional in \emph{not} |
|
96 supporting memoing.\footnote{The lack of memoing and the strict |
|
97 nature of SML requires some care when working with low-level |
|
98 sequence operations, to avoid duplicate or premature evaluation of |
|
99 results. It also means that modified runtime behavior, such as |
|
100 timeout, is very hard to achieve for general tactics.} |
|
101 |
|
102 An \emph{empty result sequence} means that the tactic has failed: in |
|
103 a compound tactic expression other tactics might be tried instead, |
|
104 or the whole refinement step might fail outright, producing a |
|
105 toplevel error message in the end. When implementing tactics from |
|
106 scratch, one should take care to observe the basic protocol of |
|
107 mapping regular error conditions to an empty result; only serious |
|
108 faults should emerge as exceptions. |
|
109 |
|
110 By enumerating \emph{multiple results}, a tactic can easily express |
|
111 the potential outcome of an internal search process. There are also |
|
112 combinators for building proof tools that involve search |
|
113 systematically, see also \secref{sec:tacticals}. |
|
114 |
|
115 \medskip As explained before, a goal state essentially consists of a |
|
116 list of subgoals that imply the main goal (conclusion). Tactics may |
|
117 operate on all subgoals or on a particularly specified subgoal, but |
|
118 must not change the main conclusion (apart from instantiating |
|
119 schematic goal variables). |
|
120 |
|
121 Tactics with explicit \emph{subgoal addressing} are of the form |
|
122 @{text "int \<rightarrow> tactic"} and may be applied to a particular subgoal |
|
123 (counting from 1). If the subgoal number is out of range, the |
|
124 tactic should fail with an empty result sequence, but must not raise |
|
125 an exception! |
|
126 |
|
127 Operating on a particular subgoal means to replace it by an interval |
|
128 of zero or more subgoals in the same place; other subgoals must not |
|
129 be affected, apart from instantiating schematic variables ranging |
|
130 over the whole goal state. |
|
131 |
|
132 A common pattern of composing tactics with subgoal addressing is to |
|
133 try the first one, and then the second one only if the subgoal has |
|
134 not been solved yet. Special care is required here to avoid bumping |
|
135 into unrelated subgoals that happen to come after the original |
|
136 subgoal. Assuming that there is only a single initial subgoal is a |
|
137 very common error when implementing tactics! |
|
138 |
|
139 Tactics with internal subgoal addressing should expose the subgoal |
|
140 index as @{text "int"} argument in full generality; a hardwired |
|
141 subgoal 1 is not acceptable. |
|
142 |
|
143 \medskip The main well-formedness conditions for proper tactics are |
|
144 summarized as follows. |
|
145 |
|
146 \begin{itemize} |
|
147 |
|
148 \item General tactic failure is indicated by an empty result, only |
|
149 serious faults may produce an exception. |
|
150 |
|
151 \item The main conclusion must not be changed, apart from |
|
152 instantiating schematic variables. |
|
153 |
|
154 \item A tactic operates either uniformly on all subgoals, or |
|
155 specifically on a selected subgoal (without bumping into unrelated |
|
156 subgoals). |
|
157 |
|
158 \item Range errors in subgoal addressing produce an empty result. |
|
159 |
|
160 \end{itemize} |
|
161 |
|
162 Some of these conditions are checked by higher-level goal |
|
163 infrastructure (\secref{sec:struct-goals}); others are not checked |
|
164 explicitly, and violating them merely results in ill-behaved tactics |
|
165 experienced by the user (e.g.\ tactics that insist in being |
|
166 applicable only to singleton goals, or prevent composition via |
|
167 standard tacticals such as @{ML REPEAT}). |
|
168 *} |
|
169 |
|
170 text %mlref {* |
|
171 \begin{mldecls} |
|
172 @{index_ML_type tactic: "thm -> thm Seq.seq"} \\ |
|
173 @{index_ML no_tac: tactic} \\ |
|
174 @{index_ML all_tac: tactic} \\ |
|
175 @{index_ML print_tac: "string -> tactic"} \\[1ex] |
|
176 @{index_ML PRIMITIVE: "(thm -> thm) -> tactic"} \\[1ex] |
|
177 @{index_ML SUBGOAL: "(term * int -> tactic) -> int -> tactic"} \\ |
|
178 @{index_ML CSUBGOAL: "(cterm * int -> tactic) -> int -> tactic"} \\ |
|
179 \end{mldecls} |
|
180 |
|
181 \begin{description} |
|
182 |
|
183 \item Type @{ML_type tactic} represents tactics. The |
|
184 well-formedness conditions described above need to be observed. See |
|
185 also @{file "~~/src/Pure/General/seq.ML"} for the underlying |
|
186 implementation of lazy sequences. |
|
187 |
|
188 \item Type @{ML_type "int -> tactic"} represents tactics with |
|
189 explicit subgoal addressing, with well-formedness conditions as |
|
190 described above. |
|
191 |
|
192 \item @{ML no_tac} is a tactic that always fails, returning the |
|
193 empty sequence. |
|
194 |
|
195 \item @{ML all_tac} is a tactic that always succeeds, returning a |
|
196 singleton sequence with unchanged goal state. |
|
197 |
|
198 \item @{ML print_tac}~@{text "message"} is like @{ML all_tac}, but |
|
199 prints a message together with the goal state on the tracing |
|
200 channel. |
|
201 |
|
202 \item @{ML PRIMITIVE}~@{text rule} turns a primitive inference rule |
|
203 into a tactic with unique result. Exception @{ML THM} is considered |
|
204 a regular tactic failure and produces an empty result; other |
|
205 exceptions are passed through. |
|
206 |
|
207 \item @{ML SUBGOAL}~@{text "(fn (subgoal, i) => tactic)"} is the |
|
208 most basic form to produce a tactic with subgoal addressing. The |
|
209 given abstraction over the subgoal term and subgoal number allows to |
|
210 peek at the relevant information of the full goal state. The |
|
211 subgoal range is checked as required above. |
|
212 |
|
213 \item @{ML CSUBGOAL} is similar to @{ML SUBGOAL}, but passes the |
|
214 subgoal as @{ML_type cterm} instead of raw @{ML_type term}. This |
|
215 avoids expensive re-certification in situations where the subgoal is |
|
216 used directly for primitive inferences. |
|
217 |
|
218 \end{description} |
|
219 *} |
|
220 |
|
221 |
|
222 subsection {* Resolution and assumption tactics \label{sec:resolve-assume-tac} *} |
|
223 |
|
224 text {* \emph{Resolution} is the most basic mechanism for refining a |
|
225 subgoal using a theorem as object-level rule. |
|
226 \emph{Elim-resolution} is particularly suited for elimination rules: |
|
227 it resolves with a rule, proves its first premise by assumption, and |
|
228 finally deletes that assumption from any new subgoals. |
|
229 \emph{Destruct-resolution} is like elim-resolution, but the given |
|
230 destruction rules are first turned into canonical elimination |
|
231 format. \emph{Forward-resolution} is like destruct-resolution, but |
|
232 without deleting the selected assumption. The @{text "r/e/d/f"} |
|
233 naming convention is maintained for several different kinds of |
|
234 resolution rules and tactics. |
|
235 |
|
236 Assumption tactics close a subgoal by unifying some of its premises |
|
237 against its conclusion. |
|
238 |
|
239 \medskip All the tactics in this section operate on a subgoal |
|
240 designated by a positive integer. Other subgoals might be affected |
|
241 indirectly, due to instantiation of schematic variables. |
|
242 |
|
243 There are various sources of non-determinism, the tactic result |
|
244 sequence enumerates all possibilities of the following choices (if |
|
245 applicable): |
|
246 |
|
247 \begin{enumerate} |
|
248 |
|
249 \item selecting one of the rules given as argument to the tactic; |
|
250 |
|
251 \item selecting a subgoal premise to eliminate, unifying it against |
|
252 the first premise of the rule; |
|
253 |
|
254 \item unifying the conclusion of the subgoal to the conclusion of |
|
255 the rule. |
|
256 |
|
257 \end{enumerate} |
|
258 |
|
259 Recall that higher-order unification may produce multiple results |
|
260 that are enumerated here. |
|
261 *} |
|
262 |
|
263 text %mlref {* |
|
264 \begin{mldecls} |
|
265 @{index_ML resolve_tac: "thm list -> int -> tactic"} \\ |
|
266 @{index_ML eresolve_tac: "thm list -> int -> tactic"} \\ |
|
267 @{index_ML dresolve_tac: "thm list -> int -> tactic"} \\ |
|
268 @{index_ML forward_tac: "thm list -> int -> tactic"} \\[1ex] |
|
269 @{index_ML assume_tac: "int -> tactic"} \\ |
|
270 @{index_ML eq_assume_tac: "int -> tactic"} \\[1ex] |
|
271 @{index_ML match_tac: "thm list -> int -> tactic"} \\ |
|
272 @{index_ML ematch_tac: "thm list -> int -> tactic"} \\ |
|
273 @{index_ML dmatch_tac: "thm list -> int -> tactic"} \\ |
|
274 \end{mldecls} |
|
275 |
|
276 \begin{description} |
|
277 |
|
278 \item @{ML resolve_tac}~@{text "thms i"} refines the goal state |
|
279 using the given theorems, which should normally be introduction |
|
280 rules. The tactic resolves a rule's conclusion with subgoal @{text |
|
281 i}, replacing it by the corresponding versions of the rule's |
|
282 premises. |
|
283 |
|
284 \item @{ML eresolve_tac}~@{text "thms i"} performs elim-resolution |
|
285 with the given theorems, which are normally be elimination rules. |
|
286 |
|
287 Note that @{ML "eresolve_tac [asm_rl]"} is equivalent to @{ML |
|
288 assume_tac}, which facilitates mixing of assumption steps with |
|
289 genuine eliminations. |
|
290 |
|
291 \item @{ML dresolve_tac}~@{text "thms i"} performs |
|
292 destruct-resolution with the given theorems, which should normally |
|
293 be destruction rules. This replaces an assumption by the result of |
|
294 applying one of the rules. |
|
295 |
|
296 \item @{ML forward_tac} is like @{ML dresolve_tac} except that the |
|
297 selected assumption is not deleted. It applies a rule to an |
|
298 assumption, adding the result as a new assumption. |
|
299 |
|
300 \item @{ML assume_tac}~@{text i} attempts to solve subgoal @{text i} |
|
301 by assumption (modulo higher-order unification). |
|
302 |
|
303 \item @{ML eq_assume_tac} is similar to @{ML assume_tac}, but checks |
|
304 only for immediate @{text "\<alpha>"}-convertibility instead of using |
|
305 unification. It succeeds (with a unique next state) if one of the |
|
306 assumptions is equal to the subgoal's conclusion. Since it does not |
|
307 instantiate variables, it cannot make other subgoals unprovable. |
|
308 |
|
309 \item @{ML match_tac}, @{ML ematch_tac}, and @{ML dmatch_tac} are |
|
310 similar to @{ML resolve_tac}, @{ML eresolve_tac}, and @{ML |
|
311 dresolve_tac}, respectively, but do not instantiate schematic |
|
312 variables in the goal state. |
|
313 |
|
314 Flexible subgoals are not updated at will, but are left alone. |
|
315 Strictly speaking, matching means to treat the unknowns in the goal |
|
316 state as constants; these tactics merely discard unifiers that would |
|
317 update the goal state. |
|
318 |
|
319 \end{description} |
|
320 *} |
|
321 |
|
322 |
|
323 subsection {* Explicit instantiation within a subgoal context *} |
|
324 |
|
325 text {* The main resolution tactics (\secref{sec:resolve-assume-tac}) |
|
326 use higher-order unification, which works well in many practical |
|
327 situations despite its daunting theoretical properties. |
|
328 Nonetheless, there are important problem classes where unguided |
|
329 higher-order unification is not so useful. This typically involves |
|
330 rules like universal elimination, existential introduction, or |
|
331 equational substitution. Here the unification problem involves |
|
332 fully flexible @{text "?P ?x"} schemes, which are hard to manage |
|
333 without further hints. |
|
334 |
|
335 By providing a (small) rigid term for @{text "?x"} explicitly, the |
|
336 remaining unification problem is to assign a (large) term to @{text |
|
337 "?P"}, according to the shape of the given subgoal. This is |
|
338 sufficiently well-behaved in most practical situations. |
|
339 |
|
340 \medskip Isabelle provides separate versions of the standard @{text |
|
341 "r/e/d/f"} resolution tactics that allow to provide explicit |
|
342 instantiations of unknowns of the given rule, wrt.\ terms that refer |
|
343 to the implicit context of the selected subgoal. |
|
344 |
|
345 An instantiation consists of a list of pairs of the form @{text |
|
346 "(?x, t)"}, where @{text ?x} is a schematic variable occurring in |
|
347 the given rule, and @{text t} is a term from the current proof |
|
348 context, augmented by the local goal parameters of the selected |
|
349 subgoal; cf.\ the @{text "focus"} operation described in |
|
350 \secref{sec:variables}. |
|
351 |
|
352 Entering the syntactic context of a subgoal is a brittle operation, |
|
353 because its exact form is somewhat accidental, and the choice of |
|
354 bound variable names depends on the presence of other local and |
|
355 global names. Explicit renaming of subgoal parameters prior to |
|
356 explicit instantiation might help to achieve a bit more robustness. |
|
357 |
|
358 Type instantiations may be given as well, via pairs like @{text |
|
359 "(?'a, \<tau>)"}. Type instantiations are distinguished from term |
|
360 instantiations by the syntactic form of the schematic variable. |
|
361 Types are instantiated before terms are. Since term instantiation |
|
362 already performs simple type-inference, so explicit type |
|
363 instantiations are seldom necessary. |
|
364 *} |
|
365 |
|
366 text %mlref {* |
|
367 \begin{mldecls} |
|
368 @{index_ML res_inst_tac: "Proof.context -> (indexname * string) list -> thm -> int -> tactic"} \\ |
|
369 @{index_ML eres_inst_tac: "Proof.context -> (indexname * string) list -> thm -> int -> tactic"} \\ |
|
370 @{index_ML dres_inst_tac: "Proof.context -> (indexname * string) list -> thm -> int -> tactic"} \\ |
|
371 @{index_ML forw_inst_tac: "Proof.context -> (indexname * string) list -> thm -> int -> tactic"} \\ |
|
372 @{index_ML subgoal_tac: "Proof.context -> string -> int -> tactic"} \\ |
|
373 @{index_ML thin_tac: "Proof.context -> string -> int -> tactic"} \\ |
|
374 @{index_ML rename_tac: "string list -> int -> tactic"} \\ |
|
375 \end{mldecls} |
|
376 |
|
377 \begin{description} |
|
378 |
|
379 \item @{ML res_inst_tac}~@{text "ctxt insts thm i"} instantiates the |
|
380 rule @{text thm} with the instantiations @{text insts}, as described |
|
381 above, and then performs resolution on subgoal @{text i}. |
|
382 |
|
383 \item @{ML eres_inst_tac} is like @{ML res_inst_tac}, but performs |
|
384 elim-resolution. |
|
385 |
|
386 \item @{ML dres_inst_tac} is like @{ML res_inst_tac}, but performs |
|
387 destruct-resolution. |
|
388 |
|
389 \item @{ML forw_inst_tac} is like @{ML dres_inst_tac} except that |
|
390 the selected assumption is not deleted. |
|
391 |
|
392 \item @{ML subgoal_tac}~@{text "ctxt \<phi> i"} adds the proposition |
|
393 @{text "\<phi>"} as local premise to subgoal @{text "i"}, and poses the |
|
394 same as a new subgoal @{text "i + 1"} (in the original context). |
|
395 |
|
396 \item @{ML thin_tac}~@{text "ctxt \<phi> i"} deletes the specified |
|
397 premise from subgoal @{text i}. Note that @{text \<phi>} may contain |
|
398 schematic variables, to abbreviate the intended proposition; the |
|
399 first matching subgoal premise will be deleted. Removing useless |
|
400 premises from a subgoal increases its readability and can make |
|
401 search tactics run faster. |
|
402 |
|
403 \item @{ML rename_tac}~@{text "names i"} renames the innermost |
|
404 parameters of subgoal @{text i} according to the provided @{text |
|
405 names} (which need to be distinct indentifiers). |
|
406 |
|
407 \end{description} |
|
408 |
|
409 For historical reasons, the above instantiation tactics take |
|
410 unparsed string arguments, which makes them hard to use in general |
|
411 ML code. The slightly more advanced @{ML Subgoal.FOCUS} combinator |
|
412 of \secref{sec:struct-goals} allows to refer to internal goal |
|
413 structure with explicit context management. |
|
414 *} |
|
415 |
|
416 |
|
417 subsection {* Rearranging goal states *} |
|
418 |
|
419 text {* In rare situations there is a need to rearrange goal states: |
|
420 either the overall collection of subgoals, or the local structure of |
|
421 a subgoal. Various administrative tactics allow to operate on the |
|
422 concrete presentation these conceptual sets of formulae. *} |
|
423 |
|
424 text %mlref {* |
|
425 \begin{mldecls} |
|
426 @{index_ML rotate_tac: "int -> int -> tactic"} \\ |
|
427 @{index_ML distinct_subgoals_tac: tactic} \\ |
|
428 @{index_ML flexflex_tac: tactic} \\ |
|
429 \end{mldecls} |
|
430 |
|
431 \begin{description} |
|
432 |
|
433 \item @{ML rotate_tac}~@{text "n i"} rotates the premises of subgoal |
|
434 @{text i} by @{text n} positions: from right to left if @{text n} is |
|
435 positive, and from left to right if @{text n} is negative. |
|
436 |
|
437 \item @{ML distinct_subgoals_tac} removes duplicate subgoals from a |
|
438 proof state. This is potentially inefficient. |
|
439 |
|
440 \item @{ML flexflex_tac} removes all flex-flex pairs from the proof |
|
441 state by applying the trivial unifier. This drastic step loses |
|
442 information. It is already part of the Isar infrastructure for |
|
443 facts resulting from goals, and rarely needs to be invoked manually. |
|
444 |
|
445 Flex-flex constraints arise from difficult cases of higher-order |
|
446 unification. To prevent this, use @{ML res_inst_tac} to instantiate |
|
447 some variables in a rule. Normally flex-flex constraints can be |
|
448 ignored; they often disappear as unknowns get instantiated. |
|
449 |
|
450 \end{description} |
|
451 *} |
|
452 |
|
453 section {* Tacticals \label{sec:tacticals} *} |
|
454 |
|
455 text {* A \emph{tactical} is a functional combinator for building up |
|
456 complex tactics from simpler ones. Common tacticals perform |
|
457 sequential composition, disjunctive choice, iteration, or goal |
|
458 addressing. Various search strategies may be expressed via |
|
459 tacticals. |
|
460 *} |
|
461 |
|
462 |
|
463 subsection {* Combining tactics *} |
|
464 |
|
465 text {* Sequential composition and alternative choices are the most |
|
466 basic ways to combine tactics, similarly to ``@{verbatim ","}'' and |
|
467 ``@{verbatim "|"}'' in Isar method notation. This corresponds to |
|
468 @{ML_op "THEN"} and @{ML_op "ORELSE"} in ML, but there are further |
|
469 possibilities for fine-tuning alternation of tactics such as @{ML_op |
|
470 "APPEND"}. Further details become visible in ML due to explicit |
|
471 subgoal addressing. |
|
472 *} |
|
473 |
|
474 text %mlref {* |
|
475 \begin{mldecls} |
|
476 @{index_ML_op "THEN": "tactic * tactic -> tactic"} \\ |
|
477 @{index_ML_op "ORELSE": "tactic * tactic -> tactic"} \\ |
|
478 @{index_ML_op "APPEND": "tactic * tactic -> tactic"} \\ |
|
479 @{index_ML "EVERY": "tactic list -> tactic"} \\ |
|
480 @{index_ML "FIRST": "tactic list -> tactic"} \\[0.5ex] |
|
481 |
|
482 @{index_ML_op "THEN'": "('a -> tactic) * ('a -> tactic) -> 'a -> tactic"} \\ |
|
483 @{index_ML_op "ORELSE'": "('a -> tactic) * ('a -> tactic) -> 'a -> tactic"} \\ |
|
484 @{index_ML_op "APPEND'": "('a -> tactic) * ('a -> tactic) -> 'a -> tactic"} \\ |
|
485 @{index_ML "EVERY'": "('a -> tactic) list -> 'a -> tactic"} \\ |
|
486 @{index_ML "FIRST'": "('a -> tactic) list -> 'a -> tactic"} \\ |
|
487 \end{mldecls} |
|
488 |
|
489 \begin{description} |
|
490 |
|
491 \item @{text "tac\<^sub>1"}~@{ML_op THEN}~@{text "tac\<^sub>2"} is the sequential |
|
492 composition of @{text "tac\<^sub>1"} and @{text "tac\<^sub>2"}. Applied to a goal |
|
493 state, it returns all states reachable in two steps by applying |
|
494 @{text "tac\<^sub>1"} followed by @{text "tac\<^sub>2"}. First, it applies @{text |
|
495 "tac\<^sub>1"} to the goal state, getting a sequence of possible next |
|
496 states; then, it applies @{text "tac\<^sub>2"} to each of these and |
|
497 concatenates the results to produce again one flat sequence of |
|
498 states. |
|
499 |
|
500 \item @{text "tac\<^sub>1"}~@{ML_op ORELSE}~@{text "tac\<^sub>2"} makes a choice |
|
501 between @{text "tac\<^sub>1"} and @{text "tac\<^sub>2"}. Applied to a state, it |
|
502 tries @{text "tac\<^sub>1"} and returns the result if non-empty; if @{text |
|
503 "tac\<^sub>1"} fails then it uses @{text "tac\<^sub>2"}. This is a deterministic |
|
504 choice: if @{text "tac\<^sub>1"} succeeds then @{text "tac\<^sub>2"} is excluded |
|
505 from the result. |
|
506 |
|
507 \item @{text "tac\<^sub>1"}~@{ML_op APPEND}~@{text "tac\<^sub>2"} concatenates the |
|
508 possible results of @{text "tac\<^sub>1"} and @{text "tac\<^sub>2"}. Unlike |
|
509 @{ML_op "ORELSE"} there is \emph{no commitment} to either tactic, so |
|
510 @{ML_op "APPEND"} helps to avoid incompleteness during search, at |
|
511 the cost of potential inefficiencies. |
|
512 |
|
513 \item @{ML EVERY}~@{text "[tac\<^sub>1, \<dots>, tac\<^sub>n]"} abbreviates @{text |
|
514 "tac\<^sub>1"}~@{ML_op THEN}~@{text "\<dots>"}~@{ML_op THEN}~@{text "tac\<^sub>n"}. |
|
515 Note that @{ML "EVERY []"} is the same as @{ML all_tac}: it always |
|
516 succeeds. |
|
517 |
|
518 \item @{ML FIRST}~@{text "[tac\<^sub>1, \<dots>, tac\<^sub>n]"} abbreviates @{text |
|
519 "tac\<^sub>1"}~@{ML_op ORELSE}~@{text "\<dots>"}~@{ML_op "ORELSE"}~@{text |
|
520 "tac\<^sub>n"}. Note that @{ML "FIRST []"} is the same as @{ML no_tac}: it |
|
521 always fails. |
|
522 |
|
523 \item @{ML_op "THEN'"} is the lifted version of @{ML_op "THEN"}, for |
|
524 tactics with explicit subgoal addressing. So @{text |
|
525 "(tac\<^sub>1"}~@{ML_op THEN'}~@{text "tac\<^sub>2) i"} is the same as @{text |
|
526 "(tac\<^sub>1 i"}~@{ML_op THEN}~@{text "tac\<^sub>2 i)"}. |
|
527 |
|
528 The other primed tacticals work analogously. |
|
529 |
|
530 \end{description} |
|
531 *} |
|
532 |
|
533 |
|
534 subsection {* Repetition tacticals *} |
|
535 |
|
536 text {* These tacticals provide further control over repetition of |
|
537 tactics, beyond the stylized forms of ``@{verbatim "?"}'' and |
|
538 ``@{verbatim "+"}'' in Isar method expressions. *} |
|
539 |
|
540 text %mlref {* |
|
541 \begin{mldecls} |
|
542 @{index_ML "TRY": "tactic -> tactic"} \\ |
|
543 @{index_ML "REPEAT": "tactic -> tactic"} \\ |
|
544 @{index_ML "REPEAT1": "tactic -> tactic"} \\ |
|
545 @{index_ML "REPEAT_DETERM": "tactic -> tactic"} \\ |
|
546 @{index_ML "REPEAT_DETERM_N": "int -> tactic -> tactic"} \\ |
|
547 \end{mldecls} |
|
548 |
|
549 \begin{description} |
|
550 |
|
551 \item @{ML TRY}~@{text "tac"} applies @{text "tac"} to the goal |
|
552 state and returns the resulting sequence, if non-empty; otherwise it |
|
553 returns the original state. Thus, it applies @{text "tac"} at most |
|
554 once. |
|
555 |
|
556 Note that for tactics with subgoal addressing, the combinator can be |
|
557 applied via functional composition: @{ML "TRY"}~@{ML_op o}~@{text |
|
558 "tac"}. There is no need for @{verbatim TRY'}. |
|
559 |
|
560 \item @{ML REPEAT}~@{text "tac"} applies @{text "tac"} to the goal |
|
561 state and, recursively, to each element of the resulting sequence. |
|
562 The resulting sequence consists of those states that make @{text |
|
563 "tac"} fail. Thus, it applies @{text "tac"} as many times as |
|
564 possible (including zero times), and allows backtracking over each |
|
565 invocation of @{text "tac"}. @{ML REPEAT} is more general than @{ML |
|
566 REPEAT_DETERM}, but requires more space. |
|
567 |
|
568 \item @{ML REPEAT1}~@{text "tac"} is like @{ML REPEAT}~@{text "tac"} |
|
569 but it always applies @{text "tac"} at least once, failing if this |
|
570 is impossible. |
|
571 |
|
572 \item @{ML REPEAT_DETERM}~@{text "tac"} applies @{text "tac"} to the |
|
573 goal state and, recursively, to the head of the resulting sequence. |
|
574 It returns the first state to make @{text "tac"} fail. It is |
|
575 deterministic, discarding alternative outcomes. |
|
576 |
|
577 \item @{ML REPEAT_DETERM_N}~@{text "n tac"} is like @{ML |
|
578 REPEAT_DETERM}~@{text "tac"} but the number of repetitions is bound |
|
579 by @{text "n"} (where @{ML "~1"} means @{text "\<infinity>"}). |
|
580 |
|
581 \end{description} |
|
582 *} |
|
583 |
|
584 text %mlex {* The basic tactics and tacticals considered above follow |
|
585 some algebraic laws: |
|
586 |
|
587 \begin{itemize} |
|
588 |
|
589 \item @{ML all_tac} is the identity element of the tactical @{ML_op |
|
590 "THEN"}. |
|
591 |
|
592 \item @{ML no_tac} is the identity element of @{ML_op "ORELSE"} and |
|
593 @{ML_op "APPEND"}. Also, it is a zero element for @{ML_op "THEN"}, |
|
594 which means that @{text "tac"}~@{ML_op THEN}~@{ML no_tac} is |
|
595 equivalent to @{ML no_tac}. |
|
596 |
|
597 \item @{ML TRY} and @{ML REPEAT} can be expressed as (recursive) |
|
598 functions over more basic combinators (ignoring some internal |
|
599 implementation tricks): |
|
600 |
|
601 \end{itemize} |
|
602 *} |
|
603 |
|
604 ML {* |
|
605 fun TRY tac = tac ORELSE all_tac; |
|
606 fun REPEAT tac st = ((tac THEN REPEAT tac) ORELSE all_tac) st; |
|
607 *} |
|
608 |
|
609 text {* If @{text "tac"} can return multiple outcomes then so can @{ML |
|
610 REPEAT}~@{text "tac"}. @{ML REPEAT} uses @{ML_op "ORELSE"} and not |
|
611 @{ML_op "APPEND"}, it applies @{text "tac"} as many times as |
|
612 possible in each outcome. |
|
613 |
|
614 \begin{warn} |
|
615 Note the explicit abstraction over the goal state in the ML |
|
616 definition of @{ML REPEAT}. Recursive tacticals must be coded in |
|
617 this awkward fashion to avoid infinite recursion of eager functional |
|
618 evaluation in Standard ML. The following attempt would make @{ML |
|
619 REPEAT}~@{text "tac"} loop: |
|
620 \end{warn} |
|
621 *} |
|
622 |
|
623 ML {* |
|
624 (*BAD -- does not terminate!*) |
|
625 fun REPEAT tac = (tac THEN REPEAT tac) ORELSE all_tac; |
|
626 *} |
|
627 |
|
628 |
|
629 subsection {* Applying tactics to subgoal ranges *} |
|
630 |
|
631 text {* Tactics with explicit subgoal addressing |
|
632 @{ML_type "int -> tactic"} can be used together with tacticals that |
|
633 act like ``subgoal quantifiers'': guided by success of the body |
|
634 tactic a certain range of subgoals is covered. Thus the body tactic |
|
635 is applied to \emph{all} subgoals, \emph{some} subgoal etc. |
|
636 |
|
637 Suppose that the goal state has @{text "n \<ge> 0"} subgoals. Many of |
|
638 these tacticals address subgoal ranges counting downwards from |
|
639 @{text "n"} towards @{text "1"}. This has the fortunate effect that |
|
640 newly emerging subgoals are concatenated in the result, without |
|
641 interfering each other. Nonetheless, there might be situations |
|
642 where a different order is desired. *} |
|
643 |
|
644 text %mlref {* |
|
645 \begin{mldecls} |
|
646 @{index_ML ALLGOALS: "(int -> tactic) -> tactic"} \\ |
|
647 @{index_ML SOMEGOAL: "(int -> tactic) -> tactic"} \\ |
|
648 @{index_ML FIRSTGOAL: "(int -> tactic) -> tactic"} \\ |
|
649 @{index_ML HEADGOAL: "(int -> tactic) -> tactic"} \\ |
|
650 @{index_ML REPEAT_SOME: "(int -> tactic) -> tactic"} \\ |
|
651 @{index_ML REPEAT_FIRST: "(int -> tactic) -> tactic"} \\ |
|
652 @{index_ML RANGE: "(int -> tactic) list -> int -> tactic"} \\ |
|
653 \end{mldecls} |
|
654 |
|
655 \begin{description} |
|
656 |
|
657 \item @{ML ALLGOALS}~@{text "tac"} is equivalent to @{text "tac |
|
658 n"}~@{ML_op THEN}~@{text "\<dots>"}~@{ML_op THEN}~@{text "tac 1"}. It |
|
659 applies the @{text tac} to all the subgoals, counting downwards. |
|
660 |
|
661 \item @{ML SOMEGOAL}~@{text "tac"} is equivalent to @{text "tac |
|
662 n"}~@{ML_op ORELSE}~@{text "\<dots>"}~@{ML_op ORELSE}~@{text "tac 1"}. It |
|
663 applies @{text "tac"} to one subgoal, counting downwards. |
|
664 |
|
665 \item @{ML FIRSTGOAL}~@{text "tac"} is equivalent to @{text "tac |
|
666 1"}~@{ML_op ORELSE}~@{text "\<dots>"}~@{ML_op ORELSE}~@{text "tac n"}. It |
|
667 applies @{text "tac"} to one subgoal, counting upwards. |
|
668 |
|
669 \item @{ML HEADGOAL}~@{text "tac"} is equivalent to @{text "tac 1"}. |
|
670 It applies @{text "tac"} unconditionally to the first subgoal. |
|
671 |
|
672 \item @{ML REPEAT_SOME}~@{text "tac"} applies @{text "tac"} once or |
|
673 more to a subgoal, counting downwards. |
|
674 |
|
675 \item @{ML REPEAT_FIRST}~@{text "tac"} applies @{text "tac"} once or |
|
676 more to a subgoal, counting upwards. |
|
677 |
|
678 \item @{ML RANGE}~@{text "[tac\<^sub>1, \<dots>, tac\<^sub>k] i"} is equivalent to |
|
679 @{text "tac\<^sub>k (i + k - 1)"}~@{ML_op THEN}~@{text "\<dots>"}~@{ML_op |
|
680 THEN}~@{text "tac\<^sub>1 i"}. It applies the given list of tactics to the |
|
681 corresponding range of subgoals, counting downwards. |
|
682 |
|
683 \end{description} |
|
684 *} |
|
685 |
|
686 |
|
687 subsection {* Control and search tacticals *} |
|
688 |
|
689 text {* A predicate on theorems @{ML_type "thm -> bool"} can test |
|
690 whether a goal state enjoys some desirable property --- such as |
|
691 having no subgoals. Tactics that search for satisfactory goal |
|
692 states are easy to express. The main search procedures, |
|
693 depth-first, breadth-first and best-first, are provided as |
|
694 tacticals. They generate the search tree by repeatedly applying a |
|
695 given tactic. *} |
|
696 |
|
697 |
|
698 text %mlref "" |
|
699 |
|
700 subsubsection {* Filtering a tactic's results *} |
|
701 |
|
702 text {* |
|
703 \begin{mldecls} |
|
704 @{index_ML FILTER: "(thm -> bool) -> tactic -> tactic"} \\ |
|
705 @{index_ML CHANGED: "tactic -> tactic"} \\ |
|
706 \end{mldecls} |
|
707 |
|
708 \begin{description} |
|
709 |
|
710 \item @{ML FILTER}~@{text "sat tac"} applies @{text "tac"} to the |
|
711 goal state and returns a sequence consisting of those result goal |
|
712 states that are satisfactory in the sense of @{text "sat"}. |
|
713 |
|
714 \item @{ML CHANGED}~@{text "tac"} applies @{text "tac"} to the goal |
|
715 state and returns precisely those states that differ from the |
|
716 original state (according to @{ML Thm.eq_thm}). Thus @{ML |
|
717 CHANGED}~@{text "tac"} always has some effect on the state. |
|
718 |
|
719 \end{description} |
|
720 *} |
|
721 |
|
722 |
|
723 subsubsection {* Depth-first search *} |
|
724 |
|
725 text {* |
|
726 \begin{mldecls} |
|
727 @{index_ML DEPTH_FIRST: "(thm -> bool) -> tactic -> tactic"} \\ |
|
728 @{index_ML DEPTH_SOLVE: "tactic -> tactic"} \\ |
|
729 @{index_ML DEPTH_SOLVE_1: "tactic -> tactic"} \\ |
|
730 \end{mldecls} |
|
731 |
|
732 \begin{description} |
|
733 |
|
734 \item @{ML DEPTH_FIRST}~@{text "sat tac"} returns the goal state if |
|
735 @{text "sat"} returns true. Otherwise it applies @{text "tac"}, |
|
736 then recursively searches from each element of the resulting |
|
737 sequence. The code uses a stack for efficiency, in effect applying |
|
738 @{text "tac"}~@{ML_op THEN}~@{ML DEPTH_FIRST}~@{text "sat tac"} to |
|
739 the state. |
|
740 |
|
741 \item @{ML DEPTH_SOLVE}@{text "tac"} uses @{ML DEPTH_FIRST} to |
|
742 search for states having no subgoals. |
|
743 |
|
744 \item @{ML DEPTH_SOLVE_1}~@{text "tac"} uses @{ML DEPTH_FIRST} to |
|
745 search for states having fewer subgoals than the given state. Thus, |
|
746 it insists upon solving at least one subgoal. |
|
747 |
|
748 \end{description} |
|
749 *} |
|
750 |
|
751 |
|
752 subsubsection {* Other search strategies *} |
|
753 |
|
754 text {* |
|
755 \begin{mldecls} |
|
756 @{index_ML BREADTH_FIRST: "(thm -> bool) -> tactic -> tactic"} \\ |
|
757 @{index_ML BEST_FIRST: "(thm -> bool) * (thm -> int) -> tactic -> tactic"} \\ |
|
758 @{index_ML THEN_BEST_FIRST: "tactic -> (thm -> bool) * (thm -> int) -> tactic -> tactic"} \\ |
|
759 \end{mldecls} |
|
760 |
|
761 These search strategies will find a solution if one exists. |
|
762 However, they do not enumerate all solutions; they terminate after |
|
763 the first satisfactory result from @{text "tac"}. |
|
764 |
|
765 \begin{description} |
|
766 |
|
767 \item @{ML BREADTH_FIRST}~@{text "sat tac"} uses breadth-first |
|
768 search to find states for which @{text "sat"} is true. For most |
|
769 applications, it is too slow. |
|
770 |
|
771 \item @{ML BEST_FIRST}~@{text "(sat, dist) tac"} does a heuristic |
|
772 search, using @{text "dist"} to estimate the distance from a |
|
773 satisfactory state (in the sense of @{text "sat"}). It maintains a |
|
774 list of states ordered by distance. It applies @{text "tac"} to the |
|
775 head of this list; if the result contains any satisfactory states, |
|
776 then it returns them. Otherwise, @{ML BEST_FIRST} adds the new |
|
777 states to the list, and continues. |
|
778 |
|
779 The distance function is typically @{ML size_of_thm}, which computes |
|
780 the size of the state. The smaller the state, the fewer and simpler |
|
781 subgoals it has. |
|
782 |
|
783 \item @{ML THEN_BEST_FIRST}~@{text "tac\<^sub>0 (sat, dist) tac"} is like |
|
784 @{ML BEST_FIRST}, except that the priority queue initially contains |
|
785 the result of applying @{text "tac\<^sub>0"} to the goal state. This |
|
786 tactical permits separate tactics for starting the search and |
|
787 continuing the search. |
|
788 |
|
789 \end{description} |
|
790 *} |
|
791 |
|
792 |
|
793 subsubsection {* Auxiliary tacticals for searching *} |
|
794 |
|
795 text {* |
|
796 \begin{mldecls} |
|
797 @{index_ML COND: "(thm -> bool) -> tactic -> tactic -> tactic"} \\ |
|
798 @{index_ML IF_UNSOLVED: "tactic -> tactic"} \\ |
|
799 @{index_ML SOLVE: "tactic -> tactic"} \\ |
|
800 @{index_ML DETERM: "tactic -> tactic"} \\ |
|
801 \end{mldecls} |
|
802 |
|
803 \begin{description} |
|
804 |
|
805 \item @{ML COND}~@{text "sat tac\<^sub>1 tac\<^sub>2"} applies @{text "tac\<^sub>1"} to |
|
806 the goal state if it satisfies predicate @{text "sat"}, and applies |
|
807 @{text "tac\<^sub>2"}. It is a conditional tactical in that only one of |
|
808 @{text "tac\<^sub>1"} and @{text "tac\<^sub>2"} is applied to a goal state. |
|
809 However, both @{text "tac\<^sub>1"} and @{text "tac\<^sub>2"} are evaluated |
|
810 because ML uses eager evaluation. |
|
811 |
|
812 \item @{ML IF_UNSOLVED}~@{text "tac"} applies @{text "tac"} to the |
|
813 goal state if it has any subgoals, and simply returns the goal state |
|
814 otherwise. Many common tactics, such as @{ML resolve_tac}, fail if |
|
815 applied to a goal state that has no subgoals. |
|
816 |
|
817 \item @{ML SOLVE}~@{text "tac"} applies @{text "tac"} to the goal |
|
818 state and then fails iff there are subgoals left. |
|
819 |
|
820 \item @{ML DETERM}~@{text "tac"} applies @{text "tac"} to the goal |
|
821 state and returns the head of the resulting sequence. @{ML DETERM} |
|
822 limits the search space by making its argument deterministic. |
|
823 |
|
824 \end{description} |
|
825 *} |
|
826 |
|
827 |
|
828 subsubsection {* Predicates and functions useful for searching *} |
|
829 |
|
830 text {* |
|
831 \begin{mldecls} |
|
832 @{index_ML has_fewer_prems: "int -> thm -> bool"} \\ |
|
833 @{index_ML Thm.eq_thm: "thm * thm -> bool"} \\ |
|
834 @{index_ML Thm.eq_thm_prop: "thm * thm -> bool"} \\ |
|
835 @{index_ML size_of_thm: "thm -> int"} \\ |
|
836 \end{mldecls} |
|
837 |
|
838 \begin{description} |
|
839 |
|
840 \item @{ML has_fewer_prems}~@{text "n thm"} reports whether @{text |
|
841 "thm"} has fewer than @{text "n"} premises. |
|
842 |
|
843 \item @{ML Thm.eq_thm}~@{text "(thm\<^sub>1, thm\<^sub>2)"} reports whether @{text |
|
844 "thm\<^sub>1"} and @{text "thm\<^sub>2"} are equal. Both theorems must have |
|
845 compatible background theories. Both theorems must have the same |
|
846 conclusions, the same set of hypotheses, and the same set of sort |
|
847 hypotheses. Names of bound variables are ignored as usual. |
|
848 |
|
849 \item @{ML Thm.eq_thm_prop}~@{text "(thm\<^sub>1, thm\<^sub>2)"} reports whether |
|
850 the propositions of @{text "thm\<^sub>1"} and @{text "thm\<^sub>2"} are equal. |
|
851 Names of bound variables are ignored. |
|
852 |
|
853 \item @{ML size_of_thm}~@{text "thm"} computes the size of @{text |
|
854 "thm"}, namely the number of variables, constants and abstractions |
|
855 in its conclusion. It may serve as a distance function for |
|
856 @{ML BEST_FIRST}. |
|
857 |
|
858 \end{description} |
|
859 *} |
|
860 |
|
861 end |
|