comparison src/Match.v @ 460:38549f152568

Proofreading pass through Chapter 14
author Adam Chlipala <adam@chlipala.net>
date Wed, 29 Aug 2012 15:04:17 -0400
parents 0650420c127b
children 4320c1a967c2
comparison
equal deleted inserted replaced
459:9fbf3b4dac29 460:38549f152568
144 end. 144 end.
145 (* begin thide *) 145 (* begin thide *)
146 Qed. 146 Qed.
147 (* end thide *) 147 (* end thide *)
148 148
149 (** 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. 149 (** 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, the whole pattern-match would fail. In Coq, we backtrack and try the next pattern, which also matches. Its body tactic succeeds, so the overall tactic succeeds as well.
150 150
151 The example shows how failure can move to a different pattern within a [match]. Failure can also trigger an attempt to find _a different way of matching a single pattern_. Consider another example: *) 151 The example shows how failure can move to a different pattern within a [match]. Failure can also trigger an attempt to find _a different way of matching a single pattern_. Consider another example: *)
152 152
153 Theorem m2 : forall P Q R : Prop, P -> Q -> R -> Q. 153 Theorem m2 : forall P Q R : Prop, P -> Q -> R -> Q.
154 intros; match goal with 154 intros; match goal with
510 Ltac inster n := 510 Ltac inster n :=
511 intuition; 511 intuition;
512 match n with 512 match n with
513 | S ?n' => 513 | S ?n' =>
514 match goal with 514 match goal with
515 | [ H : forall x : ?T, _, x : ?T |- _ ] => generalize (H x); inster n' 515 | [ H : forall x : ?T, _, y : ?T |- _ ] => generalize (H y); inster n'
516 end 516 end
517 end. 517 end.
518 (* end thide *) 518 (* end thide *)
519 519
520 (** The tactic begins by applying propositional simplification. Next, it checks if any chain length remains, failing if not. If so, it tries all possible ways of instantiating quantified hypotheses with properly typed local variables. It is critical to realize that, if the recursive call [inster n'] fails, then the [match goal] just seeks out another way of unifying its pattern against proof state. Thus, this small amount of code provides an elegant demonstration of how backtracking [match] enables exhaustive search. 520 (** The tactic begins by applying propositional simplification. Next, it checks if any chain length remains, failing if not. If so, it tries all possible ways of instantiating quantified hypotheses with properly typed local variables. It is critical to realize that, if the recursive call [inster n'] fails, then the [match goal] just seeks out another way of unifying its pattern against proof state. Thus, this small amount of code provides an elegant demonstration of how backtracking [match] enables exhaustive search.
618 | [ |- ?P /\ _ --> _ ] => search P 618 | [ |- ?P /\ _ --> _ ] => search P
619 | [ |- _ /\ ?P --> _ ] => apply comm_prem; search P 619 | [ |- _ /\ ?P --> _ ] => apply comm_prem; search P
620 | [ |- _ --> _ ] => progress (tac || (apply and_True_prem; tac)) 620 | [ |- _ --> _ ] => progress (tac || (apply and_True_prem; tac))
621 end. 621 end.
622 622
623 (** To understand how [search_prem] works, we turn first to the final [match]. If the premise begins with a conjunction, we call the [search] procedure on each of the conjuncts, or only the first conjunct, if that already yields a case where [tac] does not fail. The call [search P] expects and maintains the invariant that the premise is of the form [P /\ Q] for some [Q]. We pass [P] explicitly as a kind of decreasing induction measure, to avoid looping forever when [tac] always fails. The second [match] case calls a commutativity lemma to realize this invariant, before passing control to [search]. The final [match] case tries applying [tac] directly and then, if that fails, changes the form of the goal by adding an extraneous [True] conjunct and calls [tac] again. 623 (** To understand how [search_prem] works, we turn first to the final [match]. If the premise begins with a conjunction, we call the [search] procedure on each of the conjuncts, or only the first conjunct, if that already yields a case where [tac] does not fail. The call [search P] expects and maintains the invariant that the premise is of the form [P /\ Q] for some [Q]. We pass [P] explicitly as a kind of decreasing induction measure, to avoid looping forever when [tac] always fails. The second [match] case calls a commutativity lemma to realize this invariant, before passing control to [search]. The final [match] case tries applying [tac] directly and then, if that fails, changes the form of the goal by adding an extraneous [True] conjunct and calls [tac] again. The %\index{tactics!progress}%[progress] tactical fails when its argument tactic succeeds without changing the current subgoal.
624 624
625 The [search] function itself tries the same tricks as in the last case of the final [match]. Additionally, if neither works, it checks if [P] is a conjunction. If so, it calls itself recursively on each conjunct, first applying associativity lemmas to maintain the goal-form invariant. 625 The [search] function itself tries the same tricks as in the last case of the final [match]. Additionally, if neither works, it checks if [P] is a conjunction. If so, it calls itself recursively on each conjunct, first applying associativity lemmas to maintain the goal-form invariant.
626 626
627 We will also want a dual function [search_conc], which does tree search through an [imp] conclusion. *) 627 We will also want a dual function [search_conc], which does tree search through an [imp] conclusion. *)
628 628
703 (** %\vspace{-.15in}% [[ 703 (** %\vspace{-.15in}% [[
704 t2 = 704 t2 =
705 fun P Q : Prop => 705 fun P Q : Prop =>
706 comm_prem (assoc_prem1 (assoc_prem2 (False_prem (P:=P /\ P /\ Q) (P /\ Q)))) 706 comm_prem (assoc_prem1 (assoc_prem2 (False_prem (P:=P /\ P /\ Q) (P /\ Q))))
707 : forall P Q : Prop, Q /\ (P /\ False) /\ P --> P /\ Q 707 : forall P Q : Prop, Q /\ (P /\ False) /\ P --> P /\ Q
708
709 ]] 708 ]]
710 709
711 We can also see that [matcher] is well-suited for cases where some human intervention is needed after the automation finishes. *) 710 %\smallskip{}%We can also see that [matcher] is well-suited for cases where some human intervention is needed after the automation finishes. *)
712 711
713 Theorem t3 : forall P Q R : Prop, 712 Theorem t3 : forall P Q R : Prop,
714 P /\ Q --> Q /\ R /\ P. 713 P /\ Q --> Q /\ R /\ P.
715 matcher. 714 matcher.
716 (** [[ 715 (** [[
967 966
968 Theorem t8 : exists p : nat * nat, fst p = 3. 967 Theorem t8 : exists p : nat * nat, fst p = 3.
969 econstructor; instantiate (1 := (3, 2)); reflexivity. 968 econstructor; instantiate (1 := (3, 2)); reflexivity.
970 Qed. 969 Qed.
971 970
972 (** The [1] above is identifying an existential variable appearing in the current goal, with the last existential appearing assigned number 1, the second last assigned number 2, and so on. The named existential is replaced everywhere by the term to the right of the [:=]. 971 (** The [1] above is identifying an existential variable appearing in the current goal, with the last existential appearing assigned number 1, the second-last assigned number 2, and so on. The named existential is replaced everywhere by the term to the right of the [:=].
973 972
974 The %\index{tactics!instantiate}%[instantiate] tactic can be convenient for exploratory proving, but it leads to very brittle proof scripts that are unlikely to adapt to changing theorem statements. It is often more helpful to have a tactic that can be used to assign a value to a term that is known to be an existential. By employing a roundabout implementation technique, we can build a tactic that generalizes this functionality. In particular, our tactic [equate] will assert that two terms are equal. If one of the terms happens to be an existential, then it will be replaced everywhere with the other term. *) 973 The %\index{tactics!instantiate}%[instantiate] tactic can be convenient for exploratory proving, but it leads to very brittle proof scripts that are unlikely to adapt to changing theorem statements. It is often more helpful to have a tactic that can be used to assign a value to a term that is known to be an existential. By employing a roundabout implementation technique, we can build a tactic that generalizes this functionality. In particular, our tactic [equate] will assert that two terms are equal. If one of the terms happens to be an existential, then it will be replaced everywhere with the other term. *)
975 974
976 Ltac equate x y := 975 Ltac equate x y :=
977 let H := fresh "H" in 976 let dummy := constr:(eq_refl x : x = y) in idtac.
978 assert (H : x = y) by reflexivity; clear H. 977
979 978 (** This tactic fails if it is not possible to prove [x = y] by [eq_refl]. We check the proof only for its unification side effects, ignoring the associated variable [dummy]. With [equate], we can build a less brittle version of the prior example. *)
980 (** This tactic fails if it is not possible to prove [x = y] by [reflexivity]. We perform the proof only for its unification side effects, clearing the fact [x = y] afterward. With [equate], we can build a less brittle version of the prior example. *)
981 979
982 Theorem t9 : exists p : nat * nat, fst p = 3. 980 Theorem t9 : exists p : nat * nat, fst p = 3.
983 econstructor; match goal with 981 econstructor; match goal with
984 | [ |- fst ?x = 3 ] => equate x (3, 2) 982 | [ |- fst ?x = 3 ] => equate x (3, 2)
985 end; reflexivity. 983 end; reflexivity.