Mercurial > cpdt > repo
comparison src/Match.v @ 220:15501145d696
Ported Match
author | Adam Chlipala <adamc@hcoop.net> |
---|---|
date | Mon, 16 Nov 2009 10:32:04 -0500 |
parents | f05514cc6c0d |
children | 82eae7bc91ea |
comparison
equal
deleted
inserted
replaced
219:dbac52f5bce1 | 220:15501145d696 |
---|---|
1 (* Copyright (c) 2008, Adam Chlipala | 1 (* Copyright (c) 2008-2009, Adam Chlipala |
2 * | 2 * |
3 * This work is licensed under a | 3 * This work is licensed under a |
4 * Creative Commons Attribution-Noncommercial-No Derivative Works 3.0 | 4 * Creative Commons Attribution-Noncommercial-No Derivative Works 3.0 |
5 * Unported License. | 5 * Unported License. |
6 * The license text is available at: | 6 * The license text is available at: |
33 | 33 |
34 (** * Hint Databases *) | 34 (** * Hint Databases *) |
35 | 35 |
36 (** Another class of built-in tactics includes [auto], [eauto], and [autorewrite]. These are based on %\textit{%#<i>#hint databases#</i>#%}%, which we have seen extended in many examples so far. These tactics are important, because, in Ltac programming, we cannot create "global variables" whose values can be extended seamlessly by different modules in different source files. We have seen the advantages of hints so far, where [crush] can be defined once and for all, while still automatically applying the hints we add throughout developments. | 36 (** Another class of built-in tactics includes [auto], [eauto], and [autorewrite]. These are based on %\textit{%#<i>#hint databases#</i>#%}%, which we have seen extended in many examples so far. These tactics are important, because, in Ltac programming, we cannot create "global variables" whose values can be extended seamlessly by different modules in different source files. We have seen the advantages of hints so far, where [crush] can be defined once and for all, while still automatically applying the hints we add throughout developments. |
37 | 37 |
38 The basic hints for [auto] and [eauto] are [Hint Immediate lemma], asking to try solving a goal immediately by applying the premise-free lemma; [Resolve lemma], which does the same but may add new premises that are themselves to be subjects of proof search; [Constructor type], which acts like [Resolve] applied to every constructor of an inductive type; and [Unfold ident], which tries unfolding [ident] when it appears at the head of a proof goal. Each of these [Hint] commands may be used with a suffix, as in [Hint Resolve lemma : my_db]. This adds the hint only to the specified database, so that it would only be used by, for instance, [auto with my_db]. An additional argument to [auto] specifies the maximum depth of proof trees to search in depth-first order, as in [auto 8] or [auto 8 with my_db]. The default depth is 5. | 38 The basic hints for [auto] and [eauto] are [Hint Immediate lemma], asking to try solving a goal immediately by applying a lemma and discharging any hypotheses with a single proof step each; [Resolve lemma], which does the same but may add new premises that are themselves to be subjects of nested proof search; [Constructor type], which acts like [Resolve] applied to every constructor of an inductive type; and [Unfold ident], which tries unfolding [ident] when it appears at the head of a proof goal. Each of these [Hint] commands may be used with a suffix, as in [Hint Resolve lemma : my_db]. This adds the hint only to the specified database, so that it would only be used by, for instance, [auto with my_db]. An additional argument to [auto] specifies the maximum depth of proof trees to search in depth-first order, as in [auto 8] or [auto 8 with my_db]. The default depth is 5. |
39 | 39 |
40 All of these [Hint] commands can be issued alternatively with a more primitive hint kind, [Extern]. A few examples should do best to explain how [Hint Extern] works. *) | 40 All of these [Hint] commands can be issued alternatively with a more primitive hint kind, [Extern]. A few examples should do best to explain how [Hint Extern] works. *) |
41 | 41 |
42 Theorem bool_neq : true <> false. | 42 Theorem bool_neq : true <> false. |
43 (* begin thide *) | 43 (* begin thide *) |
44 auto. | 44 auto. |
45 | |
45 (** [crush] would have discharged this goal, but the default hint database for [auto] contains no hint that applies. *) | 46 (** [crush] would have discharged this goal, but the default hint database for [auto] contains no hint that applies. *) |
47 | |
46 Abort. | 48 Abort. |
47 | 49 |
48 (** It is hard to come up with a [bool]-specific hint that is not just a restatement of the theorem we mean to prove. Luckily, a simpler form suffices. *) | 50 (** It is hard to come up with a [bool]-specific hint that is not just a restatement of the theorem we mean to prove. Luckily, a simpler form suffices. *) |
49 | 51 |
50 Hint Extern 1 (_ <> _) => congruence. | 52 Hint Extern 1 (_ <> _) => congruence. |
65 Hypothesis both : forall x, P x /\ Q x. | 67 Hypothesis both : forall x, P x /\ Q x. |
66 | 68 |
67 Theorem forall_and : forall z, P z. | 69 Theorem forall_and : forall z, P z. |
68 (* begin thide *) | 70 (* begin thide *) |
69 crush. | 71 crush. |
72 | |
70 (** [crush] makes no progress beyond what [intros] would have accomplished. [auto] will not apply the hypothesis [both] to prove the goal, because the conclusion of [both] does not unify with the conclusion of the goal. However, we can teach [auto] to handle this kind of goal. *) | 73 (** [crush] makes no progress beyond what [intros] would have accomplished. [auto] will not apply the hypothesis [both] to prove the goal, because the conclusion of [both] does not unify with the conclusion of the goal. However, we can teach [auto] to handle this kind of goal. *) |
71 | 74 |
72 Hint Extern 1 (P ?X) => | 75 Hint Extern 1 (P ?X) => |
73 match goal with | 76 match goal with |
74 | [ H : forall x, P x /\ _ |- _ ] => apply (proj1 (H X)) | 77 | [ H : forall x, P x /\ _ |- _ ] => apply (proj1 (H X)) |
77 auto. | 80 auto. |
78 Qed. | 81 Qed. |
79 (* end thide *) | 82 (* end thide *) |
80 | 83 |
81 (** We see that an [Extern] pattern may bind unification variables that we use in the associated tactic. [proj1] is a function from the standard library for extracting a proof of [R] from a proof of [R /\ S]. *) | 84 (** We see that an [Extern] pattern may bind unification variables that we use in the associated tactic. [proj1] is a function from the standard library for extracting a proof of [R] from a proof of [R /\ S]. *) |
85 | |
82 End forall_and. | 86 End forall_and. |
83 | 87 |
84 (** After our success on this example, we might get more ambitious and seek to generalize the hint to all possible predicates [P]. | 88 (** After our success on this example, we might get more ambitious and seek to generalize the hint to all possible predicates [P]. |
85 | 89 |
86 [[ | 90 [[ |
87 Hint Extern 1 (?P ?X) => | 91 Hint Extern 1 (?P ?X) => |
88 match goal with | 92 match goal with |
89 | [ H : forall x, ?P x /\ _ |- _ ] => apply (proj1 (H X)) | 93 | [ H : forall x, P x /\ _ |- _ ] => apply (proj1 (H X)) |
90 end. | 94 end. |
91 | 95 |
92 ]] | |
93 | |
94 [[ | |
95 User error: Bound head variable | 96 User error: Bound head variable |
97 | |
96 ]] | 98 ]] |
97 | 99 |
98 Coq's [auto] hint databases work as tables mapping %\textit{%#<i>#head symbols#</i>#%}% to lists of tactics to try. Because of this, the constant head of an [Extern] pattern must be determinable statically. In our first [Extern] hint, the head symbol was [not], since [x <> y] desugars to [not (eq x y)]; and, in the second example, the head symbol was [P]. | 100 Coq's [auto] hint databases work as tables mapping %\textit{%#<i>#head symbols#</i>#%}% to lists of tactics to try. Because of this, the constant head of an [Extern] pattern must be determinable statically. In our first [Extern] hint, the head symbol was [not], since [x <> y] desugars to [not (eq x y)]; and, in the second example, the head symbol was [P]. |
99 | 101 |
100 This restriction on [Extern] hints is the main limitation of the [auto] mechanism, preventing us from using it for general context simplifications that are not keyed off of the form of the conclusion. This is perhaps just as well, since we can often code more efficient tactics with specialized Ltac programs, and we will see how in later sections of the chapter. | 102 This restriction on [Extern] hints is the main limitation of the [auto] mechanism, preventing us from using it for general context simplifications that are not keyed off of the form of the conclusion. This is perhaps just as well, since we can often code more efficient tactics with specialized Ltac programs, and we will see how in later sections of the chapter. |
123 Hint Rewrite f_g : my_db. | 125 Hint Rewrite f_g : my_db. |
124 | 126 |
125 Lemma f_f_f' : forall x, f (f (f x)) = f x. | 127 Lemma f_f_f' : forall x, f (f (f x)) = f x. |
126 intros; autorewrite with my_db. | 128 intros; autorewrite with my_db. |
127 (** [[ | 129 (** [[ |
128 | |
129 ============================ | 130 ============================ |
130 g (g (g x)) = g x | 131 g (g (g x)) = g x |
131 ]] *) | 132 ]] *) |
133 | |
132 Abort. | 134 Abort. |
133 | 135 |
134 (** Our new hint was used to rewrite the goal into a form where the old hint could no longer be applied. This "non-monotonicity" of rewrite hints contrasts with the situation for [auto], where new hints may slow down proof search but can never "break" old proofs. *) | 136 (** Our new hint was used to rewrite the goal into a form where the old hint could no longer be applied. This "non-monotonicity" of rewrite hints contrasts with the situation for [auto], where new hints may slow down proof search but can never "break" old proofs. *) |
135 | 137 |
136 Reset garden_path. | 138 Reset garden_path. |
155 subgoal 3 is: | 157 subgoal 3 is: |
156 P (f x) | 158 P (f x) |
157 subgoal 4 is: | 159 subgoal 4 is: |
158 P (f x) | 160 P (f x) |
159 ]] *) | 161 ]] *) |
162 | |
160 Abort. | 163 Abort. |
161 | 164 |
162 (** The inappropriate rule fired the same three times as before, even though we know we will not be able to prove the premises. *) | 165 (** The inappropriate rule fired the same three times as before, even though we know we will not be able to prove the premises. *) |
163 | 166 |
164 Reset garden_path. | 167 Reset garden_path. |
186 intros; autorewrite with my_db; reflexivity. | 189 intros; autorewrite with my_db; reflexivity. |
187 (* end thide *) | 190 (* end thide *) |
188 Qed. | 191 Qed. |
189 End garden_path. | 192 End garden_path. |
190 | 193 |
194 (** remove printing * *) | |
195 | |
191 (** It can also be useful to use the [autorewrite with db in *] form, which does rewriting in hypotheses, as well as in the conclusion. *) | 196 (** It can also be useful to use the [autorewrite with db in *] form, which does rewriting in hypotheses, as well as in the conclusion. *) |
197 | |
198 (** printing * $*$ *) | |
192 | 199 |
193 Lemma in_star : forall x y, f (f (f (f x))) = f (f y) | 200 Lemma in_star : forall x y, f (f (f (f x))) = f (f y) |
194 -> f x = f (f (f y)). | 201 -> f x = f (f (f y)). |
195 (* begin thide *) | 202 (* begin thide *) |
196 intros; autorewrite with my_db in *; assumption. | 203 intros; autorewrite with my_db in *; assumption. |
284 end. | 291 end. |
285 (* end thide *) | 292 (* end thide *) |
286 | 293 |
287 (** 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. | 294 (** 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. |
288 | 295 |
289 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]. | 296 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 give a name for a hypothesis to [destruct]. |
290 | 297 |
291 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]. *) | 298 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]. *) |
292 | 299 |
293 Section propositional. | 300 Section propositional. |
294 Variables P Q R : Prop. | 301 Variables P Q R : Prop. |
321 | 328 |
322 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: *) | 329 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: *) |
323 | 330 |
324 Theorem m2 : forall P Q R : Prop, P -> Q -> R -> Q. | 331 Theorem m2 : forall P Q R : Prop, P -> Q -> R -> Q. |
325 intros; match goal with | 332 intros; match goal with |
326 | [ H : _ |- _ ] => pose H | 333 | [ H : _ |- _ ] => idtac H |
327 end. | 334 end. |
328 (** [[ | 335 |
329 | 336 (** Coq prints "[H1]". By applying [idtac] with an argument, 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: *) |
330 r := H1 : R | |
331 ============================ | |
332 Q | |
333 ]] | |
334 | |
335 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: *) | |
336 | 337 |
337 (* begin thide *) | 338 (* begin thide *) |
338 match goal with | 339 match goal with |
339 | [ H : _ |- _ ] => exact H | 340 | [ H : _ |- _ ] => exact H |
340 end. | 341 end. |
404 | 405 |
405 Theorem fo : forall x, P x -> S x. | 406 Theorem fo : forall x, P x -> S x. |
406 (* begin thide *) | 407 (* begin thide *) |
407 completer. | 408 completer. |
408 (** [[ | 409 (** [[ |
409 | |
410 x : A | 410 x : A |
411 H : P x | 411 H : P x |
412 H0 : Q x | 412 H0 : Q x |
413 H3 : R x | 413 H3 : R x |
414 H4 : S x | 414 H4 : S x |
447 Hypothesis H2 : forall x, R x -> S x. | 447 Hypothesis H2 : forall x, R x -> S x. |
448 | 448 |
449 Theorem fo' : forall x, P x -> S x. | 449 Theorem fo' : forall x, P x -> S x. |
450 (* begin thide *) | 450 (* begin thide *) |
451 (** [[ | 451 (** [[ |
452 | |
453 completer'. | 452 completer'. |
454 | 453 |
455 ]] | 454 ]] |
456 | 455 |
457 Coq loops forever at this point. What went wrong? *) | 456 Coq loops forever at this point. What went wrong? *) |
457 | |
458 Abort. | 458 Abort. |
459 (* end thide *) | 459 (* end thide *) |
460 End firstorder'. | 460 End firstorder'. |
461 | 461 |
462 (** A few examples should illustrate the issue. Here we see a [match]-based proof that works fine: *) | 462 (** A few examples should illustrate the issue. Here we see a [match]-based proof that works fine: *) |
472 (** This one fails. *) | 472 (** This one fails. *) |
473 | 473 |
474 (* begin thide *) | 474 (* begin thide *) |
475 Theorem t1' : forall x : nat, x = x. | 475 Theorem t1' : forall x : nat, x = x. |
476 (** [[ | 476 (** [[ |
477 | |
478 match goal with | 477 match goal with |
479 | [ |- forall x, ?P ] => trivial | 478 | [ |- forall x, ?P ] => trivial |
480 end. | 479 end. |
481 | 480 |
482 ]] | |
483 | |
484 [[ | |
485 User error: No matching clauses for match goal | 481 User error: No matching clauses for match goal |
486 ]] *) | 482 ]] *) |
483 | |
487 Abort. | 484 Abort. |
488 (* end thide *) | 485 (* end thide *) |
489 | 486 |
490 (** The problem is that unification variables may not contain locally-bound variables. In this case, [?P] would need to be bound to [x = x], which contains the local quantified variable [x]. By using a wildcard in the earlier version, we avoided this restriction. | 487 (** The problem is that unification variables may not contain locally-bound variables. In this case, [?P] would need to be bound to [x = x], which contains the local quantified variable [x]. By using a wildcard in the earlier version, we avoided this restriction. |
491 | 488 |
507 match ls with | 504 match ls with |
508 | nil => O | 505 | nil => O |
509 | _ :: ls' => S (length ls') | 506 | _ :: ls' => S (length ls') |
510 end. | 507 end. |
511 | 508 |
512 ]] | |
513 | |
514 [[ | |
515 Error: The reference ls' was not found in the current environment | 509 Error: The reference ls' was not found in the current environment |
510 | |
516 ]] | 511 ]] |
517 | 512 |
518 At this point, we hopefully remember that pattern variable names must be prefixed by question marks in Ltac. | 513 At this point, we hopefully remember that pattern variable names must be prefixed by question marks in Ltac. |
519 | 514 |
520 [[ | 515 [[ |
522 match ls with | 517 match ls with |
523 | nil => O | 518 | nil => O |
524 | _ :: ?ls' => S (length ls') | 519 | _ :: ?ls' => S (length ls') |
525 end. | 520 end. |
526 | 521 |
527 ]] | |
528 | |
529 [[ | |
530 Error: The reference S was not found in the current environment | 522 Error: The reference S was not found in the current environment |
523 | |
531 ]] | 524 ]] |
532 | 525 |
533 The problem is that Ltac treats the expression [S (length ls')] as an invocation of a tactic [S] with argument [length ls']. We need to use a special annotation to "escape into" the Gallina parsing nonterminal. *) | 526 The problem is that Ltac treats the expression [S (length ls')] as an invocation of a tactic [S] with argument [length ls']. We need to use a special annotation to "escape into" the Gallina parsing nonterminal. *) |
534 | 527 |
535 (* begin thide *) | 528 (* begin thide *) |
543 | 536 |
544 Goal False. | 537 Goal False. |
545 let n := length (1 :: 2 :: 3 :: nil) in | 538 let n := length (1 :: 2 :: 3 :: nil) in |
546 pose n. | 539 pose n. |
547 (** [[ | 540 (** [[ |
548 | |
549 n := S (length (2 :: 3 :: nil)) : nat | 541 n := S (length (2 :: 3 :: nil)) : nat |
550 ============================ | 542 ============================ |
551 False | 543 False |
544 | |
552 ]] | 545 ]] |
553 | 546 |
554 [n] only has the length calculation unrolled one step. What has happened here is that, by escaping into the [constr] nonterminal, we referred to the [length] function of Gallina, rather than the [length] Ltac function that we are defining. *)Abort. | 547 We use the [pose] tactic, which extends the proof context with a new variable that is set equal to particular a term. We could also have used [idtac n] in place of [pose n], which would have printed the result without changing the context. |
548 | |
549 [n] only has the length calculation unrolled one step. What has happened here is that, by escaping into the [constr] nonterminal, we referred to the [length] function of Gallina, rather than the [length] Ltac function that we are defining. *) | |
550 | |
551 Abort. | |
555 | 552 |
556 Reset length. | 553 Reset length. |
557 | 554 |
558 (** The thing to remember is that Gallina terms built by tactics must be bound explicitly via [let] or a similar technique, rather than inserting Ltac calls directly in other Gallina terms. *) | 555 (** The thing to remember is that Gallina terms built by tactics must be bound explicitly via [let] or a similar technique, rather than inserting Ltac calls directly in other Gallina terms. *) |
559 | 556 |
567 | 564 |
568 Goal False. | 565 Goal False. |
569 let n := length (1 :: 2 :: 3 :: nil) in | 566 let n := length (1 :: 2 :: 3 :: nil) in |
570 pose n. | 567 pose n. |
571 (** [[ | 568 (** [[ |
572 | |
573 n := 3 : nat | 569 n := 3 : nat |
574 ============================ | 570 ============================ |
575 False | 571 False |
576 ]] *) | 572 ]] *) |
573 | |
577 Abort. | 574 Abort. |
578 (* end thide *) | 575 (* end thide *) |
579 | 576 |
580 (* EX: Write a list map function in Ltac. *) | 577 (* EX: Write a list map function in Ltac. *) |
581 | 578 |
599 | 596 |
600 Goal False. | 597 Goal False. |
601 let ls := map (nat * nat)%type ltac:(fun x => constr:(x, x)) (1 :: 2 :: 3 :: nil) in | 598 let ls := map (nat * nat)%type ltac:(fun x => constr:(x, x)) (1 :: 2 :: 3 :: nil) in |
602 pose ls. | 599 pose ls. |
603 (** [[ | 600 (** [[ |
604 | |
605 l := (1, 1) :: (2, 2) :: (3, 3) :: nil : list (nat * nat) | 601 l := (1, 1) :: (2, 2) :: (3, 3) :: nil : list (nat * nat) |
606 ============================ | 602 ============================ |
607 False | 603 False |
608 ]] *) | 604 ]] *) |
605 | |
609 Abort. | 606 Abort. |
610 (* end thide *) | 607 (* end thide *) |
611 | 608 |
612 | 609 |
613 (** * Recursive Proof Search *) | 610 (** * Recursive Proof Search *) |
638 Variable g : A -> A -> A. | 635 Variable g : A -> A -> A. |
639 | 636 |
640 Hypothesis H1 : forall x y, P (g x y) -> Q (f x). | 637 Hypothesis H1 : forall x y, P (g x y) -> Q (f x). |
641 | 638 |
642 Theorem test_inster : forall x y, P (g x y) -> Q (f x). | 639 Theorem test_inster : forall x y, P (g x y) -> Q (f x). |
643 intros; inster 2. | 640 inster 2. |
644 Qed. | 641 Qed. |
645 | 642 |
646 Hypothesis H3 : forall u v, P u /\ P v /\ u <> v -> P (g u v). | 643 Hypothesis H3 : forall u v, P u /\ P v /\ u <> v -> P (g u v). |
647 Hypothesis H4 : forall u, Q (f u) -> P u /\ P (f u). | 644 Hypothesis H4 : forall u, Q (f u) -> P u /\ P (f u). |
648 | 645 |
649 Theorem test_inster2 : forall x y, x <> y -> P x -> Q (f y) -> Q (f x). | 646 Theorem test_inster2 : forall x y, x <> y -> P x -> Q (f y) -> Q (f x). |
650 intros; inster 3. | 647 inster 3. |
651 Qed. | 648 Qed. |
652 End test_inster. | 649 End test_inster. |
653 | 650 |
654 (** The style employed in the definition of [inster] can seem very counterintuitive to functional programmers. Usually, functional programs accumulate state changes in explicit arguments to recursive functions. In Ltac, the state of the current subgoal is always implicit. Nonetheless, in contrast to general imperative programming, it is easy to undo any changes to this state, and indeed such "undoing" happens automatically at failures within [match]es. In this way, Ltac programming is similar to programming in Haskell with a stateful failure monad that supports a composition operator along the lines of the [first] tactical. | 651 (** The style employed in the definition of [inster] can seem very counterintuitive to functional programmers. Usually, functional programs accumulate state changes in explicit arguments to recursive functions. In Ltac, the state of the current subgoal is always implicit. Nonetheless, in contrast to general imperative programming, it is easy to undo any changes to this state, and indeed such "undoing" happens automatically at failures within [match]es. In this way, Ltac programming is similar to programming in Haskell with a stateful failure monad that supports a composition operator along the lines of the [first] tactical. |
655 | 652 |
788 Theorem imp_True : forall P, | 785 Theorem imp_True : forall P, |
789 P --> True. | 786 P --> True. |
790 imp. | 787 imp. |
791 Qed. | 788 Qed. |
792 | 789 |
793 (** Our final [matcher] tactic is now straightforward. First, we [intros] all variables into scope. Then we attempt simple premise simplifications, finishing the proof upon finding [False] and eliminating any existential quantifiers that we find. After that, we search through the conclusion. We remove [True] conjuncts, remove existential quantifiers by introducing unification variables for their bound variables, and search for matching premises to cancel. Finally, when no more progress is made, we see if the goal has become trivial and can be solved by [imp_True]. *) | 790 (** Our final [matcher] tactic is now straightforward. First, we [intros] all variables into scope. Then we attempt simple premise simplifications, finishing the proof upon finding [False] and eliminating any existential quantifiers that we find. After that, we search through the conclusion. We remove [True] conjuncts, remove existential quantifiers by introducing unification variables for their bound variables, and search for matching premises to cancel. Finally, when no more progress is made, we see if the goal has become trivial and can be solved by [imp_True]. In each case, we use the tactic [simple apply] in place of [apply] to use a simpler, less expensive unification algorithm. *) |
794 | 791 |
795 Ltac matcher := | 792 Ltac matcher := |
796 intros; | 793 intros; |
797 repeat search_prem ltac:(simple apply False_prem || (simple apply ex_prem; intro)); | 794 repeat search_prem ltac:(simple apply False_prem || (simple apply ex_prem; intro)); |
798 repeat search_conc ltac:(simple apply True_conc || simple eapply ex_conc | 795 repeat search_conc ltac:(simple apply True_conc || simple eapply ex_conc |
808 Qed. | 805 Qed. |
809 | 806 |
810 (** In the generated proof, we find a trace of the workings of the search tactics. *) | 807 (** In the generated proof, we find a trace of the workings of the search tactics. *) |
811 | 808 |
812 Print t2. | 809 Print t2. |
813 (** [[ | 810 (** %\vspace{-.15in}% [[ |
814 | |
815 t2 = | 811 t2 = |
816 fun P Q : Prop => | 812 fun P Q : Prop => |
817 comm_prem (assoc_prem1 (assoc_prem2 (False_prem (P:=P /\ P /\ Q) (P /\ Q)))) | 813 comm_prem (assoc_prem1 (assoc_prem2 (False_prem (P:=P /\ P /\ Q) (P /\ Q)))) |
818 : forall P Q : Prop, Q /\ (P /\ False) /\ P --> P /\ Q | 814 : forall P Q : Prop, Q /\ (P /\ False) /\ P --> P /\ Q |
819 ]] *) | 815 |
820 | 816 ]] |
821 (** We can also see that [matcher] is well-suited for cases where some human intervention is needed after the automation finishes. *) | 817 |
818 We can also see that [matcher] is well-suited for cases where some human intervention is needed after the automation finishes. *) | |
822 | 819 |
823 Theorem t3 : forall P Q R : Prop, | 820 Theorem t3 : forall P Q R : Prop, |
824 P /\ Q --> Q /\ R /\ P. | 821 P /\ Q --> Q /\ R /\ P. |
825 matcher. | 822 matcher. |
826 (** [[ | 823 (** [[ |
827 | |
828 ============================ | 824 ============================ |
829 True --> R | 825 True --> R |
826 | |
830 ]] | 827 ]] |
831 | 828 |
832 [matcher] canceled those conjuncts that it was able to cancel, leaving a simplified subgoal for us, much as [intuition] does. *) | 829 [matcher] canceled those conjuncts that it was able to cancel, leaving a simplified subgoal for us, much as [intuition] does. *) |
830 | |
833 Abort. | 831 Abort. |
834 | 832 |
835 (** [matcher] even succeeds at guessing quantifier instantiations. It is the unification that occurs in uses of the [Match] lemma that does the real work here. *) | 833 (** [matcher] even succeeds at guessing quantifier instantiations. It is the unification that occurs in uses of the [Match] lemma that does the real work here. *) |
836 | 834 |
837 Theorem t4 : forall (P : nat -> Prop) Q, (exists x, P x /\ Q) --> Q /\ (exists x, P x). | 835 Theorem t4 : forall (P : nat -> Prop) Q, (exists x, P x /\ Q) --> Q /\ (exists x, P x). |
838 matcher. | 836 matcher. |
839 Qed. | 837 Qed. |
840 | 838 |
841 Print t4. | 839 Print t4. |
842 | 840 (** %\vspace{-.15in}% [[ |
843 (** [[ | |
844 | |
845 t4 = | 841 t4 = |
846 fun (P : nat -> Prop) (Q : Prop) => | 842 fun (P : nat -> Prop) (Q : Prop) => |
847 and_True_prem | 843 and_True_prem |
848 (ex_prem (P:=fun x : nat => P x /\ Q) | 844 (ex_prem (P:=fun x : nat => P x /\ Q) |
849 (fun x : nat => | 845 (fun x : nat => |