wenzelm@30081
|
1 |
theory Tactic
|
wenzelm@30081
|
2 |
imports Base
|
wenzelm@30081
|
3 |
begin
|
wenzelm@18537
|
4 |
|
wenzelm@20452
|
5 |
chapter {* Tactical reasoning *}
|
wenzelm@18537
|
6 |
|
wenzelm@34997
|
7 |
text {* Tactical reasoning works by refining an initial claim in a
|
wenzelm@20474
|
8 |
backwards fashion, until a solved form is reached. A @{text "goal"}
|
wenzelm@20474
|
9 |
consists of several subgoals that need to be solved in order to
|
wenzelm@20474
|
10 |
achieve the main statement; zero subgoals means that the proof may
|
wenzelm@20474
|
11 |
be finished. A @{text "tactic"} is a refinement operation that maps
|
wenzelm@20474
|
12 |
a goal to a lazy sequence of potential successors. A @{text
|
wenzelm@34997
|
13 |
"tactical"} is a combinator for composing tactics. *}
|
wenzelm@18537
|
14 |
|
wenzelm@18537
|
15 |
|
wenzelm@18537
|
16 |
section {* Goals \label{sec:tactical-goals} *}
|
wenzelm@18537
|
17 |
|
wenzelm@20451
|
18 |
text {*
|
wenzelm@30084
|
19 |
Isabelle/Pure represents a goal as a theorem stating that the
|
wenzelm@30084
|
20 |
subgoals imply the main goal: @{text "A\<^sub>1 \<Longrightarrow> \<dots> \<Longrightarrow> A\<^sub>n \<Longrightarrow>
|
wenzelm@30084
|
21 |
C"}. The outermost goal structure is that of a Horn Clause: i.e.\
|
wenzelm@30084
|
22 |
an iterated implication without any quantifiers\footnote{Recall that
|
wenzelm@30084
|
23 |
outermost @{text "\<And>x. \<phi>[x]"} is always represented via schematic
|
wenzelm@30084
|
24 |
variables in the body: @{text "\<phi>[?x]"}. These variables may get
|
wenzelm@30084
|
25 |
instantiated during the course of reasoning.}. For @{text "n = 0"}
|
wenzelm@30084
|
26 |
a goal is called ``solved''.
|
wenzelm@18537
|
27 |
|
wenzelm@30087
|
28 |
The structure of each subgoal @{text "A\<^sub>i"} is that of a
|
wenzelm@30087
|
29 |
general Hereditary Harrop Formula @{text "\<And>x\<^sub>1 \<dots>
|
wenzelm@30087
|
30 |
\<And>x\<^sub>k. H\<^sub>1 \<Longrightarrow> \<dots> \<Longrightarrow> H\<^sub>m \<Longrightarrow> B"}. Here @{text
|
wenzelm@30087
|
31 |
"x\<^sub>1, \<dots>, x\<^sub>k"} are goal parameters, i.e.\
|
wenzelm@30087
|
32 |
arbitrary-but-fixed entities of certain types, and @{text
|
wenzelm@30087
|
33 |
"H\<^sub>1, \<dots>, H\<^sub>m"} are goal hypotheses, i.e.\ facts that may
|
wenzelm@30087
|
34 |
be assumed locally. Together, this forms the goal context of the
|
wenzelm@30087
|
35 |
conclusion @{text B} to be established. The goal hypotheses may be
|
wenzelm@30087
|
36 |
again arbitrary Hereditary Harrop Formulas, although the level of
|
wenzelm@30087
|
37 |
nesting rarely exceeds 1--2 in practice.
|
wenzelm@18537
|
38 |
|
wenzelm@20451
|
39 |
The main conclusion @{text C} is internally marked as a protected
|
wenzelm@30084
|
40 |
proposition, which is represented explicitly by the notation @{text
|
wenzelm@34997
|
41 |
"#C"} here. This ensures that the decomposition into subgoals and
|
wenzelm@34997
|
42 |
main conclusion is well-defined for arbitrarily structured claims.
|
wenzelm@18537
|
43 |
|
wenzelm@20451
|
44 |
\medskip Basic goal management is performed via the following
|
wenzelm@20451
|
45 |
Isabelle/Pure rules:
|
wenzelm@18537
|
46 |
|
wenzelm@18537
|
47 |
\[
|
wenzelm@18537
|
48 |
\infer[@{text "(init)"}]{@{text "C \<Longrightarrow> #C"}}{} \qquad
|
wenzelm@20547
|
49 |
\infer[@{text "(finish)"}]{@{text "C"}}{@{text "#C"}}
|
wenzelm@18537
|
50 |
\]
|
wenzelm@18537
|
51 |
|
wenzelm@18537
|
52 |
\medskip The following low-level variants admit general reasoning
|
wenzelm@18537
|
53 |
with protected propositions:
|
wenzelm@18537
|
54 |
|
wenzelm@18537
|
55 |
\[
|
wenzelm@18537
|
56 |
\infer[@{text "(protect)"}]{@{text "#C"}}{@{text "C"}} \qquad
|
wenzelm@18537
|
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"}}
|
wenzelm@18537
|
58 |
\]
|
wenzelm@18537
|
59 |
*}
|
wenzelm@18537
|
60 |
|
wenzelm@18537
|
61 |
text %mlref {*
|
wenzelm@18537
|
62 |
\begin{mldecls}
|
wenzelm@18537
|
63 |
@{index_ML Goal.init: "cterm -> thm"} \\
|
wenzelm@32207
|
64 |
@{index_ML Goal.finish: "Proof.context -> thm -> thm"} \\
|
wenzelm@18537
|
65 |
@{index_ML Goal.protect: "thm -> thm"} \\
|
wenzelm@18537
|
66 |
@{index_ML Goal.conclude: "thm -> thm"} \\
|
wenzelm@18537
|
67 |
\end{mldecls}
|
wenzelm@18537
|
68 |
|
wenzelm@18537
|
69 |
\begin{description}
|
wenzelm@18537
|
70 |
|
wenzelm@20474
|
71 |
\item @{ML "Goal.init"}~@{text C} initializes a tactical goal from
|
wenzelm@20474
|
72 |
the well-formed proposition @{text C}.
|
wenzelm@18537
|
73 |
|
wenzelm@32207
|
74 |
\item @{ML "Goal.finish"}~@{text "ctxt thm"} checks whether theorem
|
wenzelm@20474
|
75 |
@{text "thm"} is a solved goal (no subgoals), and concludes the
|
wenzelm@32207
|
76 |
result by removing the goal protection. The context is only
|
wenzelm@32207
|
77 |
required for printing error messages.
|
wenzelm@18537
|
78 |
|
wenzelm@20474
|
79 |
\item @{ML "Goal.protect"}~@{text "thm"} protects the full statement
|
wenzelm@20474
|
80 |
of theorem @{text "thm"}.
|
wenzelm@18537
|
81 |
|
wenzelm@20474
|
82 |
\item @{ML "Goal.conclude"}~@{text "thm"} removes the goal
|
wenzelm@20474
|
83 |
protection, even if there are pending subgoals.
|
wenzelm@18537
|
84 |
|
wenzelm@18537
|
85 |
\end{description}
|
wenzelm@18537
|
86 |
*}
|
wenzelm@18537
|
87 |
|
wenzelm@18537
|
88 |
|
wenzelm@18537
|
89 |
section {* Tactics *}
|
wenzelm@18537
|
90 |
|
wenzelm@28781
|
91 |
text {* A @{text "tactic"} is a function @{text "goal \<rightarrow> goal\<^sup>*\<^sup>*"} that
|
wenzelm@28781
|
92 |
maps a given goal state (represented as a theorem, cf.\
|
wenzelm@28781
|
93 |
\secref{sec:tactical-goals}) to a lazy sequence of potential
|
wenzelm@28781
|
94 |
successor states. The underlying sequence implementation is lazy
|
wenzelm@28781
|
95 |
both in head and tail, and is purely functional in \emph{not}
|
wenzelm@28781
|
96 |
supporting memoing.\footnote{The lack of memoing and the strict
|
wenzelm@28781
|
97 |
nature of SML requires some care when working with low-level
|
wenzelm@28781
|
98 |
sequence operations, to avoid duplicate or premature evaluation of
|
wenzelm@34997
|
99 |
results. It also means that modified runtime behavior, such as
|
wenzelm@34997
|
100 |
timeout, is very hard to achieve for general tactics.}
|
wenzelm@18537
|
101 |
|
wenzelm@28781
|
102 |
An \emph{empty result sequence} means that the tactic has failed: in
|
wenzelm@34997
|
103 |
a compound tactic expression other tactics might be tried instead,
|
wenzelm@28781
|
104 |
or the whole refinement step might fail outright, producing a
|
wenzelm@34997
|
105 |
toplevel error message in the end. When implementing tactics from
|
wenzelm@34997
|
106 |
scratch, one should take care to observe the basic protocol of
|
wenzelm@34997
|
107 |
mapping regular error conditions to an empty result; only serious
|
wenzelm@34997
|
108 |
faults should emerge as exceptions.
|
wenzelm@18537
|
109 |
|
wenzelm@28781
|
110 |
By enumerating \emph{multiple results}, a tactic can easily express
|
wenzelm@28781
|
111 |
the potential outcome of an internal search process. There are also
|
wenzelm@28781
|
112 |
combinators for building proof tools that involve search
|
wenzelm@28781
|
113 |
systematically, see also \secref{sec:tacticals}.
|
wenzelm@18537
|
114 |
|
wenzelm@34997
|
115 |
\medskip As explained before, a goal state essentially consists of a
|
wenzelm@34997
|
116 |
list of subgoals that imply the main goal (conclusion). Tactics may
|
wenzelm@34997
|
117 |
operate on all subgoals or on a particularly specified subgoal, but
|
wenzelm@34997
|
118 |
must not change the main conclusion (apart from instantiating
|
wenzelm@34997
|
119 |
schematic goal variables).
|
wenzelm@18537
|
120 |
|
wenzelm@28781
|
121 |
Tactics with explicit \emph{subgoal addressing} are of the form
|
wenzelm@28781
|
122 |
@{text "int \<rightarrow> tactic"} and may be applied to a particular subgoal
|
wenzelm@28781
|
123 |
(counting from 1). If the subgoal number is out of range, the
|
wenzelm@28781
|
124 |
tactic should fail with an empty result sequence, but must not raise
|
wenzelm@28781
|
125 |
an exception!
|
wenzelm@28781
|
126 |
|
wenzelm@28781
|
127 |
Operating on a particular subgoal means to replace it by an interval
|
wenzelm@28781
|
128 |
of zero or more subgoals in the same place; other subgoals must not
|
wenzelm@28781
|
129 |
be affected, apart from instantiating schematic variables ranging
|
wenzelm@28781
|
130 |
over the whole goal state.
|
wenzelm@28781
|
131 |
|
wenzelm@28781
|
132 |
A common pattern of composing tactics with subgoal addressing is to
|
wenzelm@28781
|
133 |
try the first one, and then the second one only if the subgoal has
|
wenzelm@28781
|
134 |
not been solved yet. Special care is required here to avoid bumping
|
wenzelm@28782
|
135 |
into unrelated subgoals that happen to come after the original
|
wenzelm@28782
|
136 |
subgoal. Assuming that there is only a single initial subgoal is a
|
wenzelm@28782
|
137 |
very common error when implementing tactics!
|
wenzelm@28782
|
138 |
|
wenzelm@28782
|
139 |
Tactics with internal subgoal addressing should expose the subgoal
|
wenzelm@28782
|
140 |
index as @{text "int"} argument in full generality; a hardwired
|
wenzelm@34997
|
141 |
subgoal 1 is not acceptable.
|
wenzelm@28781
|
142 |
|
wenzelm@28781
|
143 |
\medskip The main well-formedness conditions for proper tactics are
|
wenzelm@28781
|
144 |
summarized as follows.
|
wenzelm@28781
|
145 |
|
wenzelm@28781
|
146 |
\begin{itemize}
|
wenzelm@28781
|
147 |
|
wenzelm@28781
|
148 |
\item General tactic failure is indicated by an empty result, only
|
wenzelm@28781
|
149 |
serious faults may produce an exception.
|
wenzelm@28781
|
150 |
|
wenzelm@28781
|
151 |
\item The main conclusion must not be changed, apart from
|
wenzelm@28781
|
152 |
instantiating schematic variables.
|
wenzelm@28781
|
153 |
|
wenzelm@28781
|
154 |
\item A tactic operates either uniformly on all subgoals, or
|
wenzelm@28781
|
155 |
specifically on a selected subgoal (without bumping into unrelated
|
wenzelm@28781
|
156 |
subgoals).
|
wenzelm@28781
|
157 |
|
wenzelm@28781
|
158 |
\item Range errors in subgoal addressing produce an empty result.
|
wenzelm@28781
|
159 |
|
wenzelm@28781
|
160 |
\end{itemize}
|
wenzelm@28782
|
161 |
|
wenzelm@28782
|
162 |
Some of these conditions are checked by higher-level goal
|
wenzelm@34997
|
163 |
infrastructure (\secref{sec:struct-goals}); others are not checked
|
wenzelm@28782
|
164 |
explicitly, and violating them merely results in ill-behaved tactics
|
wenzelm@28782
|
165 |
experienced by the user (e.g.\ tactics that insist in being
|
wenzelm@34997
|
166 |
applicable only to singleton goals, or prevent composition via
|
wenzelm@34997
|
167 |
standard tacticals).
|
wenzelm@28782
|
168 |
*}
|
wenzelm@28782
|
169 |
|
wenzelm@28782
|
170 |
text %mlref {*
|
wenzelm@28782
|
171 |
\begin{mldecls}
|
wenzelm@28782
|
172 |
@{index_ML_type tactic: "thm -> thm Seq.seq"} \\
|
wenzelm@28783
|
173 |
@{index_ML no_tac: tactic} \\
|
wenzelm@28783
|
174 |
@{index_ML all_tac: tactic} \\
|
wenzelm@28783
|
175 |
@{index_ML print_tac: "string -> tactic"} \\[1ex]
|
wenzelm@28783
|
176 |
@{index_ML PRIMITIVE: "(thm -> thm) -> tactic"} \\[1ex]
|
wenzelm@28782
|
177 |
@{index_ML SUBGOAL: "(term * int -> tactic) -> int -> tactic"} \\
|
wenzelm@28782
|
178 |
@{index_ML CSUBGOAL: "(cterm * int -> tactic) -> int -> tactic"} \\
|
wenzelm@28782
|
179 |
\end{mldecls}
|
wenzelm@28782
|
180 |
|
wenzelm@28782
|
181 |
\begin{description}
|
wenzelm@28782
|
182 |
|
wenzelm@28782
|
183 |
\item @{ML_type tactic} represents tactics. The well-formedness
|
wenzelm@28782
|
184 |
conditions described above need to be observed. See also @{"file"
|
wenzelm@28782
|
185 |
"~~/src/Pure/General/seq.ML"} for the underlying implementation of
|
wenzelm@28782
|
186 |
lazy sequences.
|
wenzelm@28782
|
187 |
|
wenzelm@28782
|
188 |
\item @{ML_type "int -> tactic"} represents tactics with explicit
|
wenzelm@28782
|
189 |
subgoal addressing, with well-formedness conditions as described
|
wenzelm@28782
|
190 |
above.
|
wenzelm@28782
|
191 |
|
wenzelm@28783
|
192 |
\item @{ML no_tac} is a tactic that always fails, returning the
|
wenzelm@28783
|
193 |
empty sequence.
|
wenzelm@28783
|
194 |
|
wenzelm@28783
|
195 |
\item @{ML all_tac} is a tactic that always succeeds, returning a
|
wenzelm@28783
|
196 |
singleton sequence with unchanged goal state.
|
wenzelm@28783
|
197 |
|
wenzelm@28783
|
198 |
\item @{ML print_tac}~@{text "message"} is like @{ML all_tac}, but
|
wenzelm@28783
|
199 |
prints a message together with the goal state on the tracing
|
wenzelm@28783
|
200 |
channel.
|
wenzelm@28783
|
201 |
|
wenzelm@28782
|
202 |
\item @{ML PRIMITIVE}~@{text rule} turns a primitive inference rule
|
wenzelm@28782
|
203 |
into a tactic with unique result. Exception @{ML THM} is considered
|
wenzelm@28782
|
204 |
a regular tactic failure and produces an empty result; other
|
wenzelm@28782
|
205 |
exceptions are passed through.
|
wenzelm@28782
|
206 |
|
wenzelm@28782
|
207 |
\item @{ML SUBGOAL}~@{text "(fn (subgoal, i) => tactic)"} is the
|
wenzelm@28783
|
208 |
most basic form to produce a tactic with subgoal addressing. The
|
wenzelm@28782
|
209 |
given abstraction over the subgoal term and subgoal number allows to
|
wenzelm@28782
|
210 |
peek at the relevant information of the full goal state. The
|
wenzelm@28782
|
211 |
subgoal range is checked as required above.
|
wenzelm@28782
|
212 |
|
wenzelm@28782
|
213 |
\item @{ML CSUBGOAL} is similar to @{ML SUBGOAL}, but passes the
|
wenzelm@28783
|
214 |
subgoal as @{ML_type cterm} instead of raw @{ML_type term}. This
|
wenzelm@28782
|
215 |
avoids expensive re-certification in situations where the subgoal is
|
wenzelm@28782
|
216 |
used directly for primitive inferences.
|
wenzelm@28782
|
217 |
|
wenzelm@28782
|
218 |
\end{description}
|
wenzelm@18537
|
219 |
*}
|
wenzelm@18537
|
220 |
|
wenzelm@28781
|
221 |
|
wenzelm@28785
|
222 |
subsection {* Resolution and assumption tactics \label{sec:resolve-assume-tac} *}
|
wenzelm@28783
|
223 |
|
wenzelm@28783
|
224 |
text {* \emph{Resolution} is the most basic mechanism for refining a
|
wenzelm@28783
|
225 |
subgoal using a theorem as object-level rule.
|
wenzelm@28783
|
226 |
\emph{Elim-resolution} is particularly suited for elimination rules:
|
wenzelm@28783
|
227 |
it resolves with a rule, proves its first premise by assumption, and
|
wenzelm@28783
|
228 |
finally deletes that assumption from any new subgoals.
|
wenzelm@28783
|
229 |
\emph{Destruct-resolution} is like elim-resolution, but the given
|
wenzelm@28783
|
230 |
destruction rules are first turned into canonical elimination
|
wenzelm@28783
|
231 |
format. \emph{Forward-resolution} is like destruct-resolution, but
|
wenzelm@28785
|
232 |
without deleting the selected assumption. The @{text "r/e/d/f"}
|
wenzelm@28785
|
233 |
naming convention is maintained for several different kinds of
|
wenzelm@28785
|
234 |
resolution rules and tactics.
|
wenzelm@28783
|
235 |
|
wenzelm@28783
|
236 |
Assumption tactics close a subgoal by unifying some of its premises
|
wenzelm@28783
|
237 |
against its conclusion.
|
wenzelm@28783
|
238 |
|
wenzelm@28783
|
239 |
\medskip All the tactics in this section operate on a subgoal
|
wenzelm@28783
|
240 |
designated by a positive integer. Other subgoals might be affected
|
wenzelm@28783
|
241 |
indirectly, due to instantiation of schematic variables.
|
wenzelm@28783
|
242 |
|
wenzelm@28783
|
243 |
There are various sources of non-determinism, the tactic result
|
wenzelm@28783
|
244 |
sequence enumerates all possibilities of the following choices (if
|
wenzelm@28783
|
245 |
applicable):
|
wenzelm@28783
|
246 |
|
wenzelm@28783
|
247 |
\begin{enumerate}
|
wenzelm@28783
|
248 |
|
wenzelm@28783
|
249 |
\item selecting one of the rules given as argument to the tactic;
|
wenzelm@28783
|
250 |
|
wenzelm@28783
|
251 |
\item selecting a subgoal premise to eliminate, unifying it against
|
wenzelm@28783
|
252 |
the first premise of the rule;
|
wenzelm@28783
|
253 |
|
wenzelm@28783
|
254 |
\item unifying the conclusion of the subgoal to the conclusion of
|
wenzelm@28783
|
255 |
the rule.
|
wenzelm@28783
|
256 |
|
wenzelm@28783
|
257 |
\end{enumerate}
|
wenzelm@28783
|
258 |
|
wenzelm@28783
|
259 |
Recall that higher-order unification may produce multiple results
|
wenzelm@28783
|
260 |
that are enumerated here.
|
wenzelm@28783
|
261 |
*}
|
wenzelm@28783
|
262 |
|
wenzelm@28783
|
263 |
text %mlref {*
|
wenzelm@28783
|
264 |
\begin{mldecls}
|
wenzelm@28783
|
265 |
@{index_ML resolve_tac: "thm list -> int -> tactic"} \\
|
wenzelm@28783
|
266 |
@{index_ML eresolve_tac: "thm list -> int -> tactic"} \\
|
wenzelm@28783
|
267 |
@{index_ML dresolve_tac: "thm list -> int -> tactic"} \\
|
wenzelm@28783
|
268 |
@{index_ML forward_tac: "thm list -> int -> tactic"} \\[1ex]
|
wenzelm@28783
|
269 |
@{index_ML assume_tac: "int -> tactic"} \\
|
wenzelm@28783
|
270 |
@{index_ML eq_assume_tac: "int -> tactic"} \\[1ex]
|
wenzelm@28783
|
271 |
@{index_ML match_tac: "thm list -> int -> tactic"} \\
|
wenzelm@28783
|
272 |
@{index_ML ematch_tac: "thm list -> int -> tactic"} \\
|
wenzelm@28783
|
273 |
@{index_ML dmatch_tac: "thm list -> int -> tactic"} \\
|
wenzelm@28783
|
274 |
\end{mldecls}
|
wenzelm@28783
|
275 |
|
wenzelm@28783
|
276 |
\begin{description}
|
wenzelm@28783
|
277 |
|
wenzelm@28783
|
278 |
\item @{ML resolve_tac}~@{text "thms i"} refines the goal state
|
wenzelm@28783
|
279 |
using the given theorems, which should normally be introduction
|
wenzelm@28783
|
280 |
rules. The tactic resolves a rule's conclusion with subgoal @{text
|
wenzelm@28783
|
281 |
i}, replacing it by the corresponding versions of the rule's
|
wenzelm@28783
|
282 |
premises.
|
wenzelm@28783
|
283 |
|
wenzelm@28783
|
284 |
\item @{ML eresolve_tac}~@{text "thms i"} performs elim-resolution
|
wenzelm@28783
|
285 |
with the given theorems, which should normally be elimination rules.
|
wenzelm@28783
|
286 |
|
wenzelm@28783
|
287 |
\item @{ML dresolve_tac}~@{text "thms i"} performs
|
wenzelm@28783
|
288 |
destruct-resolution with the given theorems, which should normally
|
wenzelm@28783
|
289 |
be destruction rules. This replaces an assumption by the result of
|
wenzelm@28783
|
290 |
applying one of the rules.
|
wenzelm@28783
|
291 |
|
wenzelm@28783
|
292 |
\item @{ML forward_tac} is like @{ML dresolve_tac} except that the
|
wenzelm@28783
|
293 |
selected assumption is not deleted. It applies a rule to an
|
wenzelm@28783
|
294 |
assumption, adding the result as a new assumption.
|
wenzelm@28783
|
295 |
|
wenzelm@28783
|
296 |
\item @{ML assume_tac}~@{text i} attempts to solve subgoal @{text i}
|
wenzelm@28783
|
297 |
by assumption (modulo higher-order unification).
|
wenzelm@28783
|
298 |
|
wenzelm@28783
|
299 |
\item @{ML eq_assume_tac} is similar to @{ML assume_tac}, but checks
|
wenzelm@28783
|
300 |
only for immediate @{text "\<alpha>"}-convertibility instead of using
|
wenzelm@28783
|
301 |
unification. It succeeds (with a unique next state) if one of the
|
wenzelm@28783
|
302 |
assumptions is equal to the subgoal's conclusion. Since it does not
|
wenzelm@28783
|
303 |
instantiate variables, it cannot make other subgoals unprovable.
|
wenzelm@28783
|
304 |
|
wenzelm@28783
|
305 |
\item @{ML match_tac}, @{ML ematch_tac}, and @{ML dmatch_tac} are
|
wenzelm@28783
|
306 |
similar to @{ML resolve_tac}, @{ML eresolve_tac}, and @{ML
|
wenzelm@28783
|
307 |
dresolve_tac}, respectively, but do not instantiate schematic
|
wenzelm@28783
|
308 |
variables in the goal state.
|
wenzelm@28783
|
309 |
|
wenzelm@28783
|
310 |
Flexible subgoals are not updated at will, but are left alone.
|
wenzelm@28783
|
311 |
Strictly speaking, matching means to treat the unknowns in the goal
|
wenzelm@28783
|
312 |
state as constants; these tactics merely discard unifiers that would
|
wenzelm@28783
|
313 |
update the goal state.
|
wenzelm@28783
|
314 |
|
wenzelm@28783
|
315 |
\end{description}
|
wenzelm@28783
|
316 |
*}
|
wenzelm@28783
|
317 |
|
wenzelm@28783
|
318 |
|
wenzelm@28785
|
319 |
subsection {* Explicit instantiation within a subgoal context *}
|
wenzelm@28785
|
320 |
|
wenzelm@28785
|
321 |
text {* The main resolution tactics (\secref{sec:resolve-assume-tac})
|
wenzelm@28785
|
322 |
use higher-order unification, which works well in many practical
|
wenzelm@28785
|
323 |
situations despite its daunting theoretical properties.
|
wenzelm@28785
|
324 |
Nonetheless, there are important problem classes where unguided
|
wenzelm@28785
|
325 |
higher-order unification is not so useful. This typically involves
|
wenzelm@28785
|
326 |
rules like universal elimination, existential introduction, or
|
wenzelm@28785
|
327 |
equational substitution. Here the unification problem involves
|
wenzelm@28785
|
328 |
fully flexible @{text "?P ?x"} schemes, which are hard to manage
|
wenzelm@28785
|
329 |
without further hints.
|
wenzelm@28785
|
330 |
|
wenzelm@28785
|
331 |
By providing a (small) rigid term for @{text "?x"} explicitly, the
|
wenzelm@28785
|
332 |
remaining unification problem is to assign a (large) term to @{text
|
wenzelm@28785
|
333 |
"?P"}, according to the shape of the given subgoal. This is
|
wenzelm@28785
|
334 |
sufficiently well-behaved in most practical situations.
|
wenzelm@28785
|
335 |
|
wenzelm@28785
|
336 |
\medskip Isabelle provides separate versions of the standard @{text
|
wenzelm@28785
|
337 |
"r/e/d/f"} resolution tactics that allow to provide explicit
|
wenzelm@28785
|
338 |
instantiations of unknowns of the given rule, wrt.\ terms that refer
|
wenzelm@28785
|
339 |
to the implicit context of the selected subgoal.
|
wenzelm@28785
|
340 |
|
wenzelm@28785
|
341 |
An instantiation consists of a list of pairs of the form @{text
|
wenzelm@28785
|
342 |
"(?x, t)"}, where @{text ?x} is a schematic variable occurring in
|
wenzelm@28785
|
343 |
the given rule, and @{text t} is a term from the current proof
|
wenzelm@28785
|
344 |
context, augmented by the local goal parameters of the selected
|
wenzelm@28785
|
345 |
subgoal; cf.\ the @{text "focus"} operation described in
|
wenzelm@28785
|
346 |
\secref{sec:variables}.
|
wenzelm@28785
|
347 |
|
wenzelm@28785
|
348 |
Entering the syntactic context of a subgoal is a brittle operation,
|
wenzelm@28785
|
349 |
because its exact form is somewhat accidental, and the choice of
|
wenzelm@28785
|
350 |
bound variable names depends on the presence of other local and
|
wenzelm@28785
|
351 |
global names. Explicit renaming of subgoal parameters prior to
|
wenzelm@28785
|
352 |
explicit instantiation might help to achieve a bit more robustness.
|
wenzelm@28785
|
353 |
|
wenzelm@28785
|
354 |
Type instantiations may be given as well, via pairs like @{text
|
wenzelm@28785
|
355 |
"(?'a, \<tau>)"}. Type instantiations are distinguished from term
|
wenzelm@28785
|
356 |
instantiations by the syntactic form of the schematic variable.
|
wenzelm@28785
|
357 |
Types are instantiated before terms are. Since term instantiation
|
wenzelm@34997
|
358 |
already performs simple type-inference, so explicit type
|
wenzelm@28785
|
359 |
instantiations are seldom necessary.
|
wenzelm@28785
|
360 |
*}
|
wenzelm@28785
|
361 |
|
wenzelm@28785
|
362 |
text %mlref {*
|
wenzelm@28785
|
363 |
\begin{mldecls}
|
wenzelm@28785
|
364 |
@{index_ML res_inst_tac: "Proof.context -> (indexname * string) list -> thm -> int -> tactic"} \\
|
wenzelm@28785
|
365 |
@{index_ML eres_inst_tac: "Proof.context -> (indexname * string) list -> thm -> int -> tactic"} \\
|
wenzelm@28785
|
366 |
@{index_ML dres_inst_tac: "Proof.context -> (indexname * string) list -> thm -> int -> tactic"} \\
|
wenzelm@28785
|
367 |
@{index_ML forw_inst_tac: "Proof.context -> (indexname * string) list -> thm -> int -> tactic"} \\[1ex]
|
wenzelm@28785
|
368 |
@{index_ML rename_tac: "string list -> int -> tactic"} \\
|
wenzelm@28785
|
369 |
\end{mldecls}
|
wenzelm@28785
|
370 |
|
wenzelm@28785
|
371 |
\begin{description}
|
wenzelm@28785
|
372 |
|
wenzelm@28785
|
373 |
\item @{ML res_inst_tac}~@{text "ctxt insts thm i"} instantiates the
|
wenzelm@28785
|
374 |
rule @{text thm} with the instantiations @{text insts}, as described
|
wenzelm@28785
|
375 |
above, and then performs resolution on subgoal @{text i}.
|
wenzelm@28785
|
376 |
|
wenzelm@28785
|
377 |
\item @{ML eres_inst_tac} is like @{ML res_inst_tac}, but performs
|
wenzelm@28785
|
378 |
elim-resolution.
|
wenzelm@28785
|
379 |
|
wenzelm@28785
|
380 |
\item @{ML dres_inst_tac} is like @{ML res_inst_tac}, but performs
|
wenzelm@28785
|
381 |
destruct-resolution.
|
wenzelm@28785
|
382 |
|
wenzelm@28785
|
383 |
\item @{ML forw_inst_tac} is like @{ML dres_inst_tac} except that
|
wenzelm@28785
|
384 |
the selected assumption is not deleted.
|
wenzelm@28785
|
385 |
|
wenzelm@28785
|
386 |
\item @{ML rename_tac}~@{text "names i"} renames the innermost
|
wenzelm@28785
|
387 |
parameters of subgoal @{text i} according to the provided @{text
|
wenzelm@28785
|
388 |
names} (which need to be distinct indentifiers).
|
wenzelm@28785
|
389 |
|
wenzelm@28785
|
390 |
\end{description}
|
wenzelm@34997
|
391 |
|
wenzelm@34997
|
392 |
For historical reasons, the above instantiation tactics take
|
wenzelm@34997
|
393 |
unparsed string arguments, which makes them hard to use in general
|
wenzelm@34997
|
394 |
ML code. The slightly more advanced @{ML Subgoal.FOCUS} combinator
|
wenzelm@34997
|
395 |
of \secref{sec:struct-goals} allows to refer to internal goal
|
wenzelm@34997
|
396 |
structure with explicit context management.
|
wenzelm@28785
|
397 |
*}
|
wenzelm@28785
|
398 |
|
wenzelm@28785
|
399 |
|
wenzelm@28781
|
400 |
section {* Tacticals \label{sec:tacticals} *}
|
wenzelm@18537
|
401 |
|
wenzelm@18537
|
402 |
text {*
|
wenzelm@30084
|
403 |
A \emph{tactical} is a functional combinator for building up complex
|
wenzelm@30084
|
404 |
tactics from simpler ones. Typical tactical perform sequential
|
wenzelm@30084
|
405 |
composition, disjunction (choice), iteration, or goal addressing.
|
wenzelm@30084
|
406 |
Various search strategies may be expressed via tacticals.
|
wenzelm@18537
|
407 |
|
wenzelm@30084
|
408 |
\medskip FIXME
|
wenzelm@18537
|
409 |
*}
|
wenzelm@30273
|
410 |
|
wenzelm@18537
|
411 |
end
|