I'm working through CPDT, going along with the exercises from here: https://www.cis.upenn.edu/~bcpierce/courses/670Fall12/
In this case I'm on 17, here: https://www.cis.upenn.edu/~bcpierce/courses/670Fall12/HW17.v
The main relevant definition of an inductive type is here:
Inductive has_type : context -> expr -> type -> Prop :=
| T_Unit : forall ctx, has_type ctx UnitE UnitT
(* Using a separate "t = ..." parameter here eases automation: *)
| T_Var : forall ctx n t, n < length ctx ->
t = nth n ctx UnitT ->
has_type ctx (Var n) t
| T_Abs : forall ctx t1 e t2, has_type (t1 :: ctx) e t2 ->
has_type ctx (Lam t1 e) (Arrow t1 t2)
| T_App : forall ctx e1 e2 t1 t2, has_type ctx e1 (Arrow t1 t2) ->
has_type ctx e2 t1 ->
has_type ctx (App e1 e2) t2.
The exercise is that the proofs are already written, and it's up to the student to manipulate the hint database to get them to go through automatically...but I'm hitting a weird case I don't know how to think about.
Hint Constructors has_type.
Example stlc_app : has_type nil (App (App (Lam UnitT (Lam UnitT (Var 0)))
UnitE) UnitE) UnitT.
eauto 10.
Qed.
This doesn't work...but oddly, this does:
Example stlc_app : has_type nil (App (App (Lam UnitT (Lam UnitT (Var 0)))
UnitE) UnitE) UnitT.
repeat econstructor.
Qed.
Furthermore, I tried different values for eauto n and it's clear that it is just returning instantly...
I believe that eauto uses eapply x, not econstructor, but eapply T_App also works...so I'm not sure why it is short circuiting.
Note that when I run Hint Constructors has_type, I get this message:
The hint T_App will only be used by eauto, because applying T_App would leave variable t1 as unresolved existential variable.
But we are in fact using eauto, so I'm not sure what is going on. And the info command that CPDT mentions doesn't work anymore.
I tried the following hint:
Hint Extern 1 (has_type _ _ _) => econstructor.
But that didn't work, which is weird because repeat econstructor in fact solves the target.
I'd love some advice on better understanding why the Hint Extern doesn't work, as well as why the eauto isn't properly invoking the constructor. Thank you!
After applying constructors 5 times, we come up with a goal
0 < length (UnitT :: UnitT :: nil)
and this is where eauto stucks.
This kind of simple arithmetic proposition can be solved by eauto with arith hint database.
So eauto 10 with arith can solve stlc_app.
Related
I have been trying to solve the following for quite a moment now.
Require Import
Coq.Classes.Morphisms
MathClasses.interfaces.abstract_algebra
MathClasses.interfaces.vectorspace
MathClasses.misc.workaround_tactics
MathClasses.theory.setoids
MathClasses.theory.groups.
Lemma f_equiv' `{Equiv A} `{f : A -> A} :
f = f -> forall x y, x = y -> f x = f y.
Proof.
intros.
f_equiv.
assumption.
Qed.
Goal forall `{HVS : VectorSpace K V}, forall α : K, α · mon_unit = mon_unit.
Proof.
intros.
setoid_rewrite <- right_identity at 1.
setoid_rewrite <- right_inverse with (x := α · mon_unit) at 2 3.
setoid_rewrite associativity.
apply #f_equiv' with (f := fun v => v & - (α · mon_unit)).
{ cbv; intros ?? Hxy; now rewrite Hxy. }
setoid_rewrite <- distribute_l.
setoid_rewrite left_identity. (* Error: setoid rewrite failed *)
As written in the last line, the setoid_rewrite fails with this error message :
Error: setoid rewrite failed: Unable to satisfy the following constraints:
UNDEFINED EVARS:
?X6739==[K V Ke Kplus Kmult Kzero Kone Knegate Krecip Ve Vop Vunit Vnegate
sm HVS α |- relation V] (internal placeholder) {?r}
?X6740==[K V Ke Kplus Kmult Kzero Kone Knegate Krecip Ve Vop Vunit Vnegate
sm HVS α (do_subrelation:=do_subrelation)
|- Proper (equiv ==> ?r) (scalar_mult α)] (internal placeholder) {?p}
?X6840==[K V Ke Kplus Kmult Kzero Kone Knegate Krecip Ve Vop Vunit Vnegate
sm HVS α |- relation V] (internal placeholder) {?r0}
?X6841==[K V Ke Kplus Kmult Kzero Kone Knegate Krecip Ve Vop Vunit Vnegate
sm HVS α (do_subrelation:=do_subrelation)
|- Proper (?r ==> ?r0 ==> flip impl) equiv] (internal placeholder) {?p0}
?X6842==[K V Ke Kplus Kmult Kzero Kone Knegate Krecip Ve Vop Vunit Vnegate
sm HVS α |- ProperProxy ?r0 (α · mon_unit)] (internal placeholder) {?p1}
TYPECLASSES:?X6739 ?X6740 ?X6840 ?X6841 ?X6842
SHELF:||
FUTURE GOALS STACK:?X6842 ?X6841 ?X6840 ?X6740 ?X6739 ?X6611 ?X6610 ?X6609
?X6608 ?X6607 ?X6606 ?X6605||?X64 ?X62 ?X60 ?X58 ?X57 ?X56 ?X55 ?X54 ?X53
?X52 ?X51 ?X50 ?X49 ?X48 ?X47 ?X46 ?X45 ?X44 ?X43 ?X42
I have tried changing notations, using cbv, as suggested in this question.
How can I use the left_identity lemma without the error appearing ?
I'm not an expert in the details of how the unification with the implicit variables works, so I can't explain why the rewrite fails, but I've encountered it enough to at least give a "hack" solution.
Before the final "rewrite left_identity", do a
pose proof scalar_mult_proper.
As the context now contains a proof saying that it is ok to rewrite "under" scalar multiplication that the rewrite tactic is able to use, you can now finish the proof as expected with
rewrite left_identity.
reflexivity.
(Btw, you don't need the f_equiv' lemma, for this proof, simple rewriting is enough.)
To me the problem you encountered is a problem that I run into now and then. To me it is a usability-bug, or perhaps a bug in my expectation of how the instance resolution works, and I would also love a mechanistic explanation of this behaviour.
Some background for those who didn't paste the code into a Coq session to see what happens:
The goal just before the rewrite that fails is
α · (mon_unit & mon_unit) = α · mon_unit
Here "=" is notation for equiv which is Ve in this context (which is the equality relation for vectors), and · is notation for scalar_mult, and & is notation for the semigroup operation, i.e. vector addition in this case. And we want to rewrite one of the arguments of scalar_mult inside the equiv relation. Therefore we need instances of type Proper that enables this. These instances already exist. In particular we have
scalar_mult_proper
: Proper (equiv ==> equiv ==> equiv) sm
which I found with Search Proper scalar_mult. To use this instance we need a lot of implicit variables to be filled in. Here is the full list:
Print scalar_mult_proper.
scalar_mult_proper =
λ (R M : Type) (Re : Equiv R) (Rplus : Plus R) (Rmult : Mult R)
(Rzero : Zero R) (Rone : One R) (Rnegate : Negate R)
(Me : Equiv M) (Mop : SgOp M) (Munit : MonUnit M)
(Mnegate : Negate M) (sm : ScalarMult R M) (Module0 : Module R M),
let (_, _, _, _, _, _, scalar_mult_proper) := Module0 in scalar_mult_proper
: ∀ (R M : Type) (Re : Equiv R) (Rplus : Plus R)
(Rmult : Mult R) (Rzero : Zero R) (Rone : One R)
(Rnegate : Negate R) (Me : Equiv M) (Mop : SgOp M)
(Munit : MonUnit M) (Mnegate : Negate M)
(sm : ScalarMult R M),
Module R M → Proper (equiv ==> equiv ==> equiv) sm
Almost all of those values should be filled in automatically, but for some reason the setoid_rewrite fails to do that by itself.
However, when I just add a copy of this rule to the context with pose, then the implicit variables are filled in, and the setoid_rewrite can use the rule without getting confused about what values should be used for R M Rplus Rnegate Me Module and all the other the arguments to scalar_mult_proper.
I have a function whose second argument depends on its first argument, like this:
Definition is_nice (f : Formula) (pf : FProof f) : bool := true.
And I have a unification goal, like this
is_nice (some_formula ?u) (some_proof ?u) =^= is_nice f pf
.
which fails to unify when the unification starts from left to right,
but it would be unifiable when we first unify (some_proof ?u =^= pf),
infer the value for u during this unification, and then proceed to unify
some_formula ?u =^= f with the knowledge of u.
How do I make Coq solve such unification problem? I have the following ideas:
Change is_nice so that the order of parameters is different. However, I do not know how to achieve this because of the dependency between the parameters. We would need to somehow break this dependency...
Change is_nice so that it uses some canonical structure trickery to reorder the unification problems. There is some trick like that described in the extended version of Gonthier's 'How to make ad hoc proof automation less ad hoc' paper, but it does not seem to be directly applicable.
Somehow infer ?u even before the unification of that goal starts. But again, I am not sure how.
I may use UniCoq, but it is not a requirement.
As an example, consider the following piece of code:
Inductive Formula : Set :=
| f_atomic : nat -> Formula
| f_imp : Formula -> Formula -> Formula.
Inductive FProof : Formula -> Set :=
| P1 : forall (f1 f2 : Formula), FProof (f_imp f1 (f_imp f2 f1))
| MP : forall (f1 f2 : Formula), FProof f1 -> FProof (f_imp f1 f2) -> FProof f2
.
Definition is_nice (f : Formula) (pf : FProof f) : bool := true.
Lemma impl_5_is_nice': forall (n1 : nat), is_nice _ (P1 (f_atomic (n1 + 0)) (f_atomic 5)) = true.
Proof. intros. unfold is_nice. reflexivity. Qed.
Lemma impl_3_5_is_nice: is_nice _ (P1 (f_atomic 3) (f_atomic 5) ) = true.
Proof. intros.
Fail apply impl_5_is_nice'.
apply (impl_5_is_nice' 3).
Qed.
The types Formula and FProof represent formulas and proofs in a deeply-embedded logic. The proof script of Lemma impl_3_5_is_nice demostrates the problem: the first apply does not go through, because the unification of f_atomic (?n1 + 0) with f_atomic 3 fails. However, when we manually compare the goal and Lemma impl_5_is_nice', we can realize that n1 has to be 3, and so we can specialize the lemma.
Another solution would be to inspect the goal using match goal, but then the problem is that I have quite a lot of lemmas similar impl_5_is_nice', and the tactic that would do the inspection would need to understand each one of these lemmas. Ideally, this would be unified using type classes or canonical structures, but this is really a 'backup plan'.
I am trying to prove this:
Lemma eq_eq: forall (U: Type) (p: U) (eqv: p = p), eq_refl = eqv.
But there just seems to be no way to do it. The problem is the type p = p being an equality on the same term, and then trying to match its instance. If this were not the case, it is easy enough to prove that a term of a type with a single constructor is equal to that constructor.
Lemma eq_tt: forall (U: Type) (x: unit), tt = x.
Proof
fun (U: Type) (x: unit) =>
match x as x'
return tt = x'
with tt => eq_refl
end.
But when you try the same strategy on my problem, it fails.
Lemma eq_eq: forall (U: Type) (p: U) (eqv: p = p), eq_refl = eqv.
Proof
fun (U: Type) (p: U) (eqv: p = p) =>
match eqv as e
in _ = p'
return eq_refl = e
with eq_refl => eq_refl
end.
This fails with The term "e" has type "p = p'" while it is expected to have type "p = p" (cannot unify "p'" and "p").
The problem is that the return clause here translates internally to a predicate function something like this:
fun (p': U) (e: p = p') =>
eq_refl = e
which fails to typecheck because we have now lost the constraint between the 2 terms in e's equality and eq_refl requires that constraint.
Is there any way around this problem? Am I missing something?
Your proposed lemma is precisely the statement of uniqueness of identity proofs (UIP). It was first proven that the negation of UIP is consistent in MLTT with Hofmann and Streicher's groupoid model (pdf link). In this model, types are interpreted as groupoids, where the identity type x = y is the set of morphisms from x to y in the groupoid. In this model, there can be more than one distinct e: x = y.
More recently, homotopy type theory has embraced this point of view. Rather than mere groupoids, types are interpreted as ∞-groupoids, with not only the possibility of multiple equalities between x and y, but also possibly multiple identities between identities p q: x = y, etc.
Suffice to say, your lemma isn't provable without an extra axiom such as UIP mentioned above or Axiom K.
I have been struggling on this for a while now. I have an inductive type:
Definition char := nat.
Definition string := list char.
Inductive Exp : Set :=
| Lit : char -> Exp
| And : Exp -> Exp -> Exp
| Or : Exp -> Exp -> Exp
| Many: Exp -> Exp
from which I define a family of types inductively:
Inductive Language : Exp -> Set :=
| LangLit : forall c:char, Language (Lit c)
| LangAnd : forall r1 r2: Exp, Language(r1) -> Language(r2) -> Language(And r1 r2)
| LangOrLeft : forall r1 r2: Exp, Language(r1) -> Language(Or r1 r2)
| LangOrRight : forall r1 r2: Exp, Language(r2) -> Language(Or r1 r2)
| LangEmpty : forall r: Exp, Language (Many r)
| LangMany : forall r: Exp, Language (Many r) -> Language r -> Language (Many r).
The rational here is that given a regular expression r:Exp I am attempting to represent the language associated with r as a type Language r, and I am doing so with a single inductive definition.
I would like to prove:
Lemma L1 : forall (c:char)(x:Language (Lit c)),
x = LangLit c.
(In other words, the type Language (Lit c) has only one element, i.e. the language of the regular expression 'c' is made of the single string "c". Of course I need to define some semantics converting elements of Language r to string)
Now the specifics of this problem are not important and simply serve to motivate my question: let us use nat instead of Exp and let us define a type List n which represents the lists of length n:
Parameter A:Set.
Inductive List : nat -> Set :=
| ListNil : List 0
| ListCons : forall (n:nat), A -> List n -> List (S n).
Here again I am using a single inductive definition to define a family of types List n.
I would like to prove:
Lemma L2: forall (x: List 0),
x = ListNil.
(in other words, the type List 0 has only one element).
I have run out of ideas on this one.
Normally when attempting to prove (negative) results with inductive types (or predicates), I would use the elim tactic (having made sure all the relevant hypothesis are inside my goal (generalize) and only variables occur in the type constructors). But elim is no good in this case.
If you are willing to accept more than just the basic logic of Coq, you can just use the dependent destruction tactic, available in the Program library (I've taken the liberty of rephrasing your last example in terms of standard-library vectors):
Require Coq.Vectors.Vector.
Require Import Program.
Lemma l0 A (v : Vector.t A 0) : v = #Vector.nil A.
Proof.
now dependent destruction v.
Qed.
If you inspect the term, you'll see that this tactic relied on the JMeq_eq axiom to get the proof to go through:
Print Assumptions l0.
Axioms:
JMeq_eq : forall (A : Type) (x y : A), x ~= y -> x = y
Fortunately, it is possible to prove l0 without having to resort to features outside of Coq's basic logic, by making a small change to the statement of the previous lemma.
Lemma l0_gen A n (v : Vector.t A n) :
match n return Vector.t A n -> Prop with
| 0 => fun v => v = #Vector.nil A
| _ => fun _ => True
end v.
Proof.
now destruct v.
Qed.
Lemma l0' A (v : Vector.t A 0) : v = #Vector.nil A.
Proof.
exact (l0_gen A 0 v).
Qed.
We can see that this new proof does not require any additional axioms:
Print Assumptions l0'.
Closed under the global context
What happened here? The problem, roughly speaking, is that in Coq we cannot perform case analysis on terms of dependent types whose indices have a specific shape (such as 0, in your case) directly. Instead, we must prove a more general statement where the problematic indices are replaced by variables. This is exactly what the l0_gen lemma is doing. Notice how we had to make the match on n return a function that abstracts on v. This is another instance of what is known as "convoy pattern". Had we written
match n with
| 0 => v = #Vector.nil A
| _ => True
end.
Coq would see the v in the 0 branch as having type Vector.t A n, making that branch ill-typed.
Coming up with such generalizations is one of the big pains of doing dependently typed programming in Coq. Other systems, such as Agda, make it possible to write this kind of code with much less effort, but it was only recently shown that this can be done without relying on the extra axioms that Coq wanted to avoid including in its basic theory. We can only hope that this will be simplified in future versions.
Ever since I learned a little bit of Coq I wanted to learn to write a Coq proof of the so-called division algorithm that is actually a logical proposition: forall n m : nat, exists q : nat, exists r : nat, n = q * m + r
I recently accomplished that task using what I learned from Software Foundations.
Coq being a system for developing constructive proofs, my proof is in effect a method to construct suitable values q and r from values m and n.
Coq has an intriguing facility for "extracting" an algorithm in Coq's algorithm language (Gallina) to general-purpose functional programming languages including Haskell.
Separately I have managed to write the divmod operation as a Gallina Fixpoint and extract that. I want to note carefully that that task is not what I'm considering here.
Adam Chlipala has written in Certified Programming with Dependent Types that "Many fans of the Curry-Howard correspondence support the idea of extracting programs from proofs. In reality, few users of Coq and related tools do any such thing."
Is it even possible to extract the algorithm implicit in my proof to Haskell? If it is possible, how would it be done?
Thanks to Prof. Pierce's summer 2012 video 4.1 as Dan Feltey suggested, we see that the key is that the theorem to be extracted must provide a member of Type rather than the usual kind of propositions, which is Prop.
For the particular theorem the affected construct is the inductive Prop ex and its notation exists. Similarly to what Prof. Pierce has done, we can state our own alternate definitions ex_t and exists_t that replace occurrences of Prop with occurrences of Type.
Here is the usual redefinition of ex and exists similarly as they are defined in Coq's standard library.
Inductive ex (X:Type) (P : X->Prop) : Prop :=
ex_intro : forall (witness:X), P witness -> ex X P.
Notation "'exists' x : X , p" := (ex _ (fun x:X => p))
(at level 200, x ident, right associativity) : type_scope.
Here are the alternate definitions.
Inductive ex_t (X:Type) (P : X->Type) : Type :=
ex_t_intro : forall (witness:X), P witness -> ex_t X P.
Notation "'exists_t' x : X , p" := (ex_t _ (fun x:X => p))
(at level 200, x ident, right associativity) : type_scope.
Now, somewhat unfortunately, it is necessary to repeat both the statement and the proof of the theorem using these new definitions.
What in the world??
Why is it necessary to make a reiterated statement of the theorem and a reiterated proof of the theorem, that differ only by using an alternative definition of the quantifier??
I had hoped to use the existing theorem in Prop to prove the theorem over again in Type. That strategy fails when Coq rejects the proof tactic inversion for a Prop in the environment when that Prop uses exists and the goal is a Type that uses exists_t. Coq reports "Error: Inversion would require case analysis on sort Set which is not allowed
for inductive definition ex." This behavior occurred in Coq 8.3. I am not certain that it
still occurs in Coq 8.4.
I think the need to repeat the proof is actually profound although I doubt that I personally am quite managing to perceive its profundity. It involves the facts that Prop is "impredicative" and Type is not impredicative, but rather, tacitly "stratified". Predicativity is (if I understand correctly) vulnerability to Russell's paradox that the set S of sets that are not members of themselves can neither be a member of S, nor a non-member of S. Type avoids Russell's paradox by tacitly creating a sequence of higher types that contain lower types. Because Coq is drenched in the formulae-as-types interpretation of the Curry-Howard correspondence, and if I am getting this right, we can even understand stratification of types in Coq as a way to avoid Gödel incompleteness, the phenomenon that certain formulae express constraints on formulae such as themselves and thereby become unknowable as to their truth or falsehood.
Back on planet Earth, here is the repeated statement of the theorem using "exists_t".
Theorem divalg_t : forall n m : nat, exists_t q : nat,
exists_t r : nat, n = plus (mult q m) r.
As I have omitted the proof of divalg, I will also omit the proof of divalg_t. I will only mention that we do have the good fortune that proof tactics including "exists" and "inversion" work just the same with our new definitions "ex_t" and "exists_t".
Finally, the extraction itself is accomplished easily.
Extraction Language Haskell.
Extraction "divalg.hs" divalg_t.
The resulting Haskell file contains a number of definitions, the heart of which is the reasonably nice code, below. And I was only slightly hampered by my near-total ignorance of the Haskell programming language. Note that Ex_t_intro creates a result whose type is Ex_t; O and S are the zero and the successor function from Peano arithmetic; beq_nat tests Peano numbers for equality; nat_rec is a higher-order function that recurs over the function among its arguments. The definition of nat_rec is not shown here. At any rate it is generated by Coq according to the inductive type "nat" that was defined in Coq.
divalg :: Nat -> Nat -> Ex_t Nat (Ex_t Nat ())
divalg n m =
case m of {
O -> Ex_t_intro O (Ex_t_intro n __);
S m' ->
nat_rec (Ex_t_intro O (Ex_t_intro O __)) (\n' iHn' ->
case iHn' of {
Ex_t_intro q' hq' ->
case hq' of {
Ex_t_intro r' _ ->
let {k = beq_nat r' m'} in
case k of {
True -> Ex_t_intro (S q') (Ex_t_intro O __);
False -> Ex_t_intro q' (Ex_t_intro (S r') __)}}}) n}
Update 2013-04-24: I know a bit more Haskell now. To assist others in reading the extracted code above, I'm presenting the following hand-rewritten code that I claim is equivalent and more readable. I'm also presenting the extracted definitions Nat, O, S, and nat_rec that I did not eliminate.
-- Extracted: Natural numbers (non-negative integers)
-- in the manner in which Peano defined them.
data Nat =
O
| S Nat
deriving (Eq, Show)
-- Extracted: General recursion over natural numbers,
-- an interpretation of Nat in the manner of higher-order abstract syntax.
nat_rec :: a1 -> (Nat -> a1 -> a1) -> Nat -> a1
nat_rec f f0 n =
case n of {
O -> f;
S n0 -> f0 n0 (nat_rec f f0 n0)}
-- Given non-negative integers n and m, produce (q, r) with n = q * m + r.
divalg_t :: Nat -> Nat -> (Nat, Nat)
divalg_t n O = (O, n) -- n/0: Define quotient 0, remainder n.
divalg_t n (S m') = divpos n m' -- n/(S m')
where
-- Given non-negative integers n and m',
-- and defining m = m' + 1,
-- produce (q, r) with n = q * m + r
-- so that q = floor (n / m) and r = n % m.
divpos :: Nat -> Nat -> (Nat, Nat)
divpos n m' = nat_rec (O, O) (incrDivMod m') n
-- Given a non-negative integer m' and
-- a pair of non-negative integers (q', r') with r <= m',
-- and defining m = m' + 1,
-- produce (q, r) with q*m + r = q'*m + r' + 1 and r <= m'.
incrDivMod :: Nat -> Nat -> (Nat, Nat) -> (Nat, Nat)
incrDivMod m' _ (q', r')
| r' == m' = (S q', O)
| otherwise = (q', S r')
The current copy of Software Foundations dated July 25, 2012, answers this quite concisely in the late chapter "Extraction2". The answer is that it can certainly be done, much like this:
Extraction Language Haskell
Extraction "divalg.hs" divalg
One more trick is necessary. Instead of a Prop, divalg must be a Type. Otherwise it will be erased in the process of extraction.
Uh oh, #Anthill is correct, I haven't answered the question because I don't know how to explain how Prof. Pierce accomplished that in his NormInType.v variant of his Norm.v and MoreStlc.v.
OK, here's the rest of my partial answer anyway.
Where "divalg" appears above, it will be necessary to provide a space-separated list of all of the propositions (which must each be redefined as a Type rather than a Prop) on which divalg relies. For a thorough, interesting, and working example of a proof extraction, one may consult the chapter Extraction2 mentioned above. That example extracts to OCaml, but adapting it for Haskell is simply a matter of using Extraction Language Haskell as above.
In part, the reason that I spent some time not knowing the above answer is that I have been using the copy of Software Foundations dated October 14, 2010, that I downloaded in 2011.