comparison src/Match.v @ 135:091583baf345

Through completer'
author Adam Chlipala <adamc@hcoop.net>
date Sun, 26 Oct 2008 14:11:41 -0400
parents f9d8f33c9b46
children d6b1e9de7fc1
comparison
equal deleted inserted replaced
134:f9d8f33c9b46 135:091583baf345
182 -> f x = f (f (f y)). 182 -> f x = f (f (f y)).
183 intros; autorewrite with my_db in *; assumption. 183 intros; autorewrite with my_db in *; assumption.
184 Qed. 184 Qed.
185 185
186 End autorewrite. 186 End autorewrite.
187
188
189 (** * Ltac Programming Basics *)
190
191 (** We have already seen many examples of Ltac programs. In the rest of this chapter, we attempt to give a more principled introduction to the important features and design patterns.
192
193 One common use for [match] tactics is identification of subjects for case analysis, as we see in this tactic definition. *)
194
195 Ltac find_if :=
196 match goal with
197 | [ |- if ?X then _ else _ ] => destruct X
198 end.
199
200 (** The tactic checks if the conclusion is an [if], [destruct]ing the test expression if so. Certain classes of theorem are trivial to prove automatically with such a tactic. *)
201
202 Theorem hmm : forall (a b c : bool),
203 if a
204 then if b
205 then True
206 else True
207 else if c
208 then True
209 else True.
210 intros; repeat find_if; constructor.
211 Qed.
212
213 (** The [repeat] that we use here is called a %\textit{%#<i>#tactical#</i>#%}%, or tactic combinator. The behavior of [repeat t] is to loop through running [t], running [t] on all generated subgoals, running [t] on %\textit{%#<i>#their#</i>#%}% generated subgoals, and so on. When [t] fails at any point in this search tree, that particular subgoal is left to be handled by later tactics. Thus, it is important never to use [repeat] with a tactic that always succeeds.
214
215 Another very useful Ltac building block is %\textit{%#<i>#context patterns#</i>#%}%. *)
216
217 Ltac find_if_inside :=
218 match goal with
219 | [ |- context[if ?X then _ else _] ] => destruct X
220 end.
221
222 (** The behavior of this tactic is to find any subterm of the conclusion that is an [if] and then [destruct] the test expression. This version subsumes [find_if]. *)
223
224 Theorem hmm' : forall (a b c : bool),
225 if a
226 then if b
227 then True
228 else True
229 else if c
230 then True
231 else True.
232 intros; repeat find_if_inside; constructor.
233 Qed.
234
235 (** We can also use [find_if_inside] to prove goals that [find_if] does not simplify sufficiently. *)
236
237 Theorem duh2 : forall (a b : bool),
238 (if a then 42 else 42) = (if b then 42 else 42).
239 intros; repeat find_if_inside; reflexivity.
240 Qed.
241
242 (** Many decision procedures can be coded in Ltac via "[repeat match] loops." For instance, we can implement a subset of the functionality of [tauto]. *)
243
244 Ltac my_tauto :=
245 repeat match goal with
246 | [ H : ?P |- ?P ] => exact H
247
248 | [ |- True ] => constructor
249 | [ |- _ /\ _ ] => constructor
250 | [ |- _ -> _ ] => intro
251
252 | [ H : False |- _ ] => destruct H
253 | [ H : _ /\ _ |- _ ] => destruct H
254 | [ H : _ \/ _ |- _ ] => destruct H
255
256 | [ H1 : ?P -> ?Q, H2 : ?P |- _ ] =>
257 let H := fresh "H" in
258 generalize (H1 H2); clear H1; intro H
259 end.
260
261 (** Since [match] patterns can share unification variables between hypothesis and conclusion patterns, it is easy to figure out when the conclusion matches a hypothesis. The [exact] tactic solves a goal completely when given a proof term of the proper type.
262
263 It is also trivial to implement the "introduction rules" for a few of the connectives. Implementing elimination rules is only a little more work, since we must bind a name for a hypothesis to [destruct].
264
265 The last rule implements modus ponens. The most interesting part is the use of the Ltac-level [let] with a [fresh] expression. [fresh] takes in a name base and returns a fresh hypothesis variable based on that name. We use the new name variable [H] as the name we assign to the result of modus ponens. The use of [generalize] changes our conclusion to be an implication from [Q]. We clear the original hypothesis and move [Q] into the context with name [H]. *)
266
267 Section propositional.
268 Variables P Q R : Prop.
269
270 Theorem and_comm : (P \/ Q \/ False) /\ (P -> Q) -> True /\ Q.
271 my_tauto.
272 Qed.
273 End propositional.
274
275 (** It was relatively easy to implement modus ponens, because we do not lose information by clearing every implication that we use. If we want to implement a similarly-complete procedure for quantifier instantiation, we need a way to ensure that a particular proposition is not already included among our hypotheses. To do that effectively, we first need to learn a bit more about the semantics of [match].
276
277 It is tempting to assume that [match] works like it does in ML. In fact, there are a few critical differences in its behavior. One is that we may include arbitrary expressions in patterns, instead of being restricted to variables and constructors. Another is that the same variable may appear multiple times, inducing an implicit equality constraint.
278
279 There is a related pair of two other differences that are much more important than the others. [match] has a %\textit{%#<i>#backtracking semantics for failure#</i>#%}%. In ML, pattern matching works by finding the first pattern to match and then executing its body. If the body raises an exception, then the overall match raises the same exception. In Coq, failures in case bodies instead trigger continued search through the list of cases.
280
281 For instance, this (unnecessarily verbose) proof script works: *)
282
283 Theorem m1 : True.
284 match goal with
285 | [ |- _ ] => intro
286 | [ |- True ] => constructor
287 end.
288 Qed.
289
290 (** The first case matches trivially, but its body tactic fails, since the conclusion does not begin with a quantifier or implication. In a similar ML match, that would mean that the whole pattern-match fails. In Coq, we backtrack and try the next pattern, which also matches. Its body tactic succeeds, so the overall tactic succeeds as well.
291
292 The example shows how failure can move to a different pattern within a [match]. Failure can also trigger an attempt to find %\textit{%#<i>#a different way of matching a single pattern#</i>#%}%. Consider another example: *)
293
294 Theorem m2 : forall P Q R : Prop, P -> Q -> R -> Q.
295 intros; match goal with
296 | [ H : _ |- _ ] => pose H
297 end.
298 (** [[
299
300 r := H1 : R
301 ============================
302 Q
303 ]]
304
305 By applying [pose], a convenient debugging tool for "leaking information out of [match]es," we see that this [match] first tries binding [H] to [H1], which cannot be used to prove [Q]. Nonetheless, the following variation on the tactic succeeds at proving the goal: *)
306
307 match goal with
308 | [ H : _ |- _ ] => exact H
309 end.
310 Qed.
311
312 (** The tactic first unifies [H] with [H1], as before, but [exact H] fails in that case, so the tactic engine searches for more possible values of [H]. Eventually, it arrives at the correct value, so that [exact H] and the overall tactic succeed. *)
313
314 (** Now we are equipped to implement a tactic for checking that a proposition is not among our hypotheses: *)
315
316 Ltac notHyp P :=
317 match goal with
318 | [ _ : P |- _ ] => fail 1
319 | _ =>
320 match P with
321 | ?P1 /\ ?P2 => first [ notHyp P1 | notHyp P2 | fail 2 ]
322 | _ => idtac
323 end
324 end.
325
326 (** We use the equality checking that is built into pattern-matching to see if there is a hypothesis that matches the proposition exactly. If so, we use the [fail] tactic. Without arguments, [fail] signals normal tactic failure, as you might expect. When [fail] is passed an argument [n], [n] is used to count outwards through the enclosing cases of backtracking search. In this case, [fail 1] says "fail not just in this pattern-matching branch, but for the whole [match]." The second case will never be tried when the [fail 1] is reached.
327
328 This second case, used when [P] matches no hypothesis, checks if [P] is a conjunction. Other simplifications may have split conjunctions into their component formulas, so we need to check that at least one of those components is also not represented. To achieve this, we apply the [first] tactical, which takes a list of tactics and continues down the list until one of them does not fail. The [fail 2] at the end says to [fail] both the [first] and the [match] wrapped around it.
329
330 The body of the [?P1 /\ ?P2] case guarantees that, if it is reached, we either succeed completely or fail completely. Thus, if we reach the wildcard case, [P] is not a conjunction. We use [idtac], a tactic that would be silly to apply on its own, since its effect is to succeed at doing nothing. Nonetheless, [idtac] is a useful placeholder for cases like what we see here.
331
332 With the non-presence check implemented, it is easy to build a tactic that takes as input a proof term and adds its conclusion as a new hypothesis, only if that conclusion is not already present, failing otherwise. *)
333
334 Ltac extend pf :=
335 let t := type of pf in
336 notHyp t; generalize pf; intro.
337
338 (** We see the useful [type of] operator of Ltac. This operator could not be implemented in Gallina, but it is easy to support in Ltac. We end up with [t] bound to the type of [pf]. We check that [t] is not already present. If so, we use a [generalize]/[intro] combo to add a new hypothesis proved by [pf].
339
340 With these tactics defined, we can write a tactic [completer] for adding to the context all consequences of a set of simple first-order formulas. *)
341
342 Ltac completer :=
343 repeat match goal with
344 | [ |- _ /\ _ ] => constructor
345 | [ H : _ /\ _ |- _ ] => destruct H
346 | [ H : ?P -> ?Q, H' : ?P |- _ ] =>
347 generalize (H H'); clear H; intro H
348 | [ |- forall x, _ ] => intro
349
350 | [ H : forall x, ?P x -> _, H' : ?P ?X |- _ ] =>
351 extend (H X H')
352 end.
353
354 (** We use the same kind of conjunction and implication handling as previously. Note that, since [->] is the special non-dependent case of [forall], the fourth rule handles [intro] for implications, too.
355
356 In the fifth rule, when we find a [forall] fact [H] with a premise matching one of our hypotheses, we add the appropriate instantiation of [H]'s conclusion, if we have not already added it.
357
358 We can check that [completer] is working properly: *)
359
360 Section firstorder.
361 Variable A : Set.
362 Variables P Q R S : A -> Prop.
363
364 Hypothesis H1 : forall x, P x -> Q x /\ R x.
365 Hypothesis H2 : forall x, R x -> S x.
366
367 Theorem fo : forall x, P x -> S x.
368 completer.
369 (** [[
370
371 x : A
372 H : P x
373 H0 : Q x
374 H3 : R x
375 H4 : S x
376 ============================
377 S x
378 ]] *)
379
380 assumption.
381 Qed.
382 End firstorder.
383
384 (** We narrowly avoided a subtle pitfall in our definition of [completer]. Let us try another definition that even seems preferable to the original, to the untrained eye. *)
385
386 Ltac completer' :=
387 repeat match goal with
388 | [ |- _ /\ _ ] => constructor
389 | [ H : _ /\ _ |- _ ] => destruct H
390 | [ H : ?P -> _, H' : ?P |- _ ] =>
391 generalize (H H'); clear H; intro H
392 | [ |- forall x, _ ] => intro
393
394 | [ H : forall x, ?P x -> _, H' : ?P ?X |- _ ] =>
395 extend (H X H')
396 end.
397
398 (** The only difference is in the modus ponens rule, where we have replaced an unused unification variable [?Q] with a wildcard. Let us try our example again with this version: *)
399
400 Section firstorder'.
401 Variable A : Set.
402 Variables P Q R S : A -> Prop.
403
404 Hypothesis H1 : forall x, P x -> Q x /\ R x.
405 Hypothesis H2 : forall x, R x -> S x.
406
407 Theorem fo' : forall x, P x -> S x.
408 (** [[
409
410 completer'.
411
412 Coq loops forever at this point. What went wrong? *)
413 Abort.
414 End firstorder'.