Mercurial > cpdt > repo
changeset 385:bef6fb896edd
More discussion of axiom avoidance and tactic pitfalls for JMeq
author | Adam Chlipala <adam@chlipala.net> |
---|---|
date | Thu, 12 Apr 2012 12:11:29 -0400 |
parents | eb0fa506d04c |
children | b911d0df5eee |
files | src/Equality.v |
diffstat | 1 files changed, 111 insertions(+), 2 deletions(-) [+] |
line wrap: on
line diff
--- a/src/Equality.v Sun Apr 08 11:11:27 2012 -0400 +++ b/src/Equality.v Thu Apr 12 12:11:29 2012 -0400 @@ -739,9 +739,118 @@ intros f f0 H; rewrite H; reflexivity. Qed. (* end thide *) -End fhapp'. -(** This example illustrates a general pattern: heterogeneous equality often simplifies theorem statements, but we still need to do some work to line up some dependent pattern matches that tactics will generate for us. *) +End fhapp'. + +(** This example illustrates a general pattern: heterogeneous equality often simplifies theorem statements, but we still need to do some work to line up some dependent pattern matches that tactics will generate for us. + + The proof we have found relies on the [JMeq_eq] axiom, which we can verify with a command%\index{Vernacular commands!Print Assumptions}% that we will discuss more in two chapters. *) + +Print Assumptions fhapp_ass'. +(** %\vspace{-.15in}%[[ +Axioms: +JMeq_eq : forall (A : Type) (x y : A), x == y -> x = y +]] + +It was the [rewrite H] tactic that implicitly appealed to the axiom. By restructuring the proof, we can avoid axiom dependence. A general lemma about pairs provides the key element. (Our use of [generalize] above can be thought of as reducing the proof to another, more complex and specialized lemma.) *) + +Lemma pair_cong : forall A1 A2 B1 B2 (x1 : A1) (x2 : A2) (y1 : B1) (y2 : B2), + x1 == x2 + -> y1 == y2 + -> (x1, y1) == (x2, y2). + intros until y2; intros Hx Hy; rewrite Hx; rewrite Hy; reflexivity. +Qed. + +Hint Resolve pair_cong. + +Section fhapp''. + Variable A : Type. + Variable B : A -> Type. + + Theorem fhapp_ass'' : forall ls1 ls2 ls3 (hls1 : fhlist B ls1) (hls2 : fhlist B ls2) + (hls3 : fhlist B ls3), + fhapp hls1 (fhapp hls2 hls3) == fhapp (fhapp hls1 hls2) hls3. + induction ls1; crush. + Qed. +End fhapp''. + +Print Assumptions fhapp_ass''. +(** << +Closed under the global context +>> + +One might wonder exactly which elements of a proof involving [JMeq] imply that [JMeq_eq] must be used. For instance, above we noticed that [rewrite] had brought [JMeq_eq] into the proof of [fhap_ass'], yet here we have also used [rewrite] with [JMeq] hypotheses while avoiding axioms! One illuminating exercise is comparing the types of the lemmas that [rewrite] uses under the hood to implement the rewrites. Here is the normal lemma for [eq] rewriting:%\index{Gallina terms!eq\_ind\_r}% *) + +Check eq_ind_r. +(** %\vspace{-.15in}%[[ +eq_ind_r + : forall (A : Type) (x : A) (P : A -> Prop), + P x -> forall y : A, y = x -> P y +]] + +The corresponding lemma used for [JMeq] in the proof of [pair_cong] is %\index{Gallina terms!JMeq\_rew\_r}%[JMeq_rew_r], which, confusingly, is defined by [rewrite] as needed, so it is not available for checking until after we apply it. *) + +Check JMeq_rew_r. +(** %\vspace{-.15in}%[[ +JMeq_rew_r + : forall (A : Type) (x : A) (B : Type) (b : B) + (P : forall B0 : Type, B0 -> Type), P B b -> x == b -> P A x +]] + +The key difference is that, where the [eq] lemma is parametrized on a predicate of type [A -> Prop], the [JMeq] lemma is parameterized on a predicate of type more like [forall A : Type, A -> Prop]. To apply [eq_ind_r] with a proof of [x = y], it is only necessary to rearrange the goal into an application of a [fun] abstraction to [y]. In contrast, to apply [JMeq_rew_r], it is necessary to rearrange the goal to an application of a [fun] abstraction to both [y] and %\emph{%#<i>#its type#</i>#%}%. In other words, the predicate must be %\emph{%#<i>#polymorphic#</i>#%}% in [y]'s type; any type must make sense, from a type-checking standpoint. There may be cases where the former rearrangement is easy to do in a type-correct way, but the second rearrangement done naively leads to a type error. + +When [rewrite] cannot figure out how to apply [JMeq_rew_r] for [x == y] where [x] and [y] have the same type, the tactic can instead use an alternate theorem, which is easy to prove as a composition of [eq_ind_r] and [JMeq_eq]. *) + +Check JMeq_ind_r. +(** %\vspace{-.15in}%[[ +JMeq_ind_r + : forall (A : Type) (x : A) (P : A -> Prop), + P x -> forall y : A, y == x -> P y +]] + +Ironically, where in the proof of [fhapp_ass'] we used [rewrite app_ass] to make it clear that a use of [JMeq] was actually homogeneously typed, we created a situation where [rewrite] applied the axiom-based [JMeq_ind_r] instead of the axiom-free [JMeq_rew_r]! + +For another simple example, consider this theorem that applies a heterogeneous equality to prove a congruence fact. *) + +Theorem out_of_luck : forall n m : nat, + n == m + -> S n == S m. + intros n m H. + + (** Applying [JMeq_ind_r] is easy, as the %\index{tactics!pattern}%[pattern] tactic will transform the goal into an application of an appropriate [fun] to a term that we want to abstract. *) + + pattern n. + (** %\vspace{-.15in}%[[ + n : nat + m : nat + H : n == m + ============================ + (fun n0 : nat => S n0 == S m) n +]] +*) + apply JMeq_ind_r with (x := m); auto. + + (** However, we run into trouble trying to get the goal into a form compatible with [JMeq_rew_r.] *) + Undo 2. +(** %\vspace{-.15in}%[[ + pattern nat, n. +]] +<< +Error: The abstracted term "fun (P : Set) (n0 : P) => S n0 == S m" +is not well typed. +Illegal application (Type Error): +The term "S" of type "nat -> nat" +cannot be applied to the term + "n0" : "P" +This term has type "P" which should be coercible to +"nat". +>> + +In other words, the successor function [S] is insufficiently polymorphic. If we try to generalize over the type of [n], we find that [S] is no longer legal to apply to [n]. *) + +Abort. + +(** Why did we not run into this problem in our proof of [fhapp_ass'']? The reason is that the pair constructor is polymorphic in the types of the pair components, while functions like [S] are not polymorphic at all. Use of such non-polymorphic functions with [JMeq] tends to push toward use of axioms. The example with [nat] here is a bit unrealistic; more likely cases would involve functions that have %\emph{%#<i>#some#</i>#%}% polymorphism, but not enough to allow abstractions of the sort we attempted above with [pattern]. For instance, we might have an equality between two lists, where the goal only type-checks when the terms involved really are lists, though everything is polymorphic in the types of list data elements. The #<a href="http://www.mpi-sws.org/~gil/Heq/">#Heq%\footnote{\url{http://www.mpi-sws.org/~gil/Heq/}}%#</a># library builds up a slightly different foundation to help avoid such problems. *) (** * Equivalence of Equality Axioms *)