Applying a Program Definition fails with "unable to unify Prop with [goal]"
Question
In Coq, I showed the associativity of append on vectors using:
Require Import Coq.Vectors.VectorDef Coq.micromega.Lia. Program Definition t_app_assoc v p q r (a : t v p) (b : t v q) (c : t v r) := append (append a b) c = append a (append b c).lia. Qed.v: Type
p, q, r: nat
a: t v p
b: t v q
c: t v rp + (q + r) = p + q + r
I now want to apply this equality in a proof. Below is the easiest goal that I would expect to be provable with t_app_assoc. Of course it can be proven by simpl - this is just an example.
This apply fails:
append (append (nil nat) (nil nat)) (nil nat) = append (nil nat) (append (nil nat) (nil nat))
How can I apply t_app_assoc? Or is there a better way to define it? I thought I needed a Program Definition, because simply using a Lemma leads to a type error because t v (p + (q + r)) and t v (p + q + r) are not the same to Coq.
Answer
Prologue
I guess what you want to to is to prove that the vector concatenation is associative and then use that fact as a lemma.
But t_app_assoc as you define it has the following type:
You basically want to use : instead of := as follows.
From Coq Require Import Vector Arith. Import VectorNotations. Import EqNotations. (* rew notation, see below *) Require Import Coq.Program.Equality. (* heterogeneous equality *) Section Append. Variable A : Type. Variable p q r : nat. Variables (a : t A p) (b : t A q) (c : t A r).
Unfortunately, we cannot even state a lemma like this using the usual homogeneous equality.
The left-hand side has the following type:
whereas the right-hand side is of type
Since t A (p + q + r) is not the same as t A (p + (q + r)) we cannot use = to state the above lemma.
Let me describe some ways of working around this issue:
rew notation
Admitted.A: Type
p, q, r: nat
a: t A p
b: t A q
c: t A r(a ++ b) ++ c = rew [t A] Nat.add_assoc p q r in (a ++ b ++ c)
Here we just use the law of associativity of addition for natural numbers to cast the type of RHS to t A (p + q + r).
To make it work one needs to Import EqNotations. before.
cast function
This is a common problem, so the authors of the Vector library decided to provide a cast function with the following type:
Let me show how one can use it to prove the law of associativity for vectors. But let's prove the following auxiliary lemma first:
A: Type
p, q, r: nat
a: t A p
b: t A q
c: t A r
X: Type
n: nat
v: t X n
e: n = ncast v e = vinduction v as [|??? IH]; simpl; rewrite ?IH; reflexivity. Qed.A: Type
p, q, r: nat
a: t A p
b: t A q
c: t A r
X: Type
n: nat
v: t X n
e: n = ncast v e = v
Now we are all set:
A: Type
p, q, r: nat
a: t A p
b: t A q
c: t A r(a ++ b) ++ c = cast (a ++ b ++ c) (Nat.add_assoc p q r)A: Type
p, q, r: nat
a: t A p
b: t A q
c: t A r(a ++ b) ++ c = cast (a ++ b ++ c) (Nat.add_assoc p q r)A: Type
p, q, r: nat
a: t A p
b: t A q
c: t A rforall e : p + (q + r) = p + q + r, (a ++ b) ++ c = cast (a ++ b ++ c) eA: Type
q, r: nat
a: t A 0
b: t A q
c: t A r
e: 0 + (q + r) = 0 + q + r([] ++ b) ++ c = cast ([] ++ b ++ c) eA: Type
q, r, p': nat
a: t A (S p')
b: t A q
c: t A r
h: A
a': t A p'
IH: t A p' -> forall e : p' + (q + r) = p' + q + r, (a' ++ b) ++ c = cast (a' ++ b ++ c) e
e: S p' + (q + r) = S p' + q + r((h :: a') ++ b) ++ c = cast ((h :: a') ++ b ++ c) enow rewrite uncast.A: Type
q, r: nat
a: t A 0
b: t A q
c: t A r
e: 0 + (q + r) = 0 + q + r([] ++ b) ++ c = cast ([] ++ b ++ c) eA: Type
q, r, p': nat
a: t A (S p')
b: t A q
c: t A r
h: A
a': t A p'
IH: t A p' -> forall e : p' + (q + r) = p' + q + r, (a' ++ b) ++ c = cast (a' ++ b ++ c) e
e: S p' + (q + r) = S p' + q + r((h :: a') ++ b) ++ c = cast ((h :: a') ++ b ++ c) eA: Type
q, r, p': nat
a: t A (S p')
b: t A q
c: t A r
h: A
a': t A p'
IH: t A p' -> forall e : p' + (q + r) = p' + q + r, (a' ++ b) ++ c = cast (a' ++ b ++ c) e
e: S p' + (q + r) = S p' + q + rh :: (a' ++ b) ++ c = h :: cast (a' ++ b ++ c) (f_equal Init.Nat.pred e)now apply IH. Qed.A: Type
q, r, p': nat
a: t A (S p')
b: t A q
c: t A r
h: A
a': t A p'
IH: t A p' -> forall e : p' + (q + r) = p' + q + r, (a' ++ b) ++ c = cast (a' ++ b ++ c) e
e: S p' + (q + r) = S p' + q + r(a' ++ b) ++ c = cast (a' ++ b ++ c) (f_equal Init.Nat.pred e)
Heterogeneous equality (a.k.a. John Major equality)
Admitted. End Append.A: Type
p, q, r: nat
a: t A p
b: t A q
c: t A r(a ++ b) ++ c ~= a ++ b ++ c
If you compare the definition of the homogeneous equality
and the definition of heterogeneous equality
you will see that with JMeq the LHS and RHS don't have to be of the same type and this is why the statement of t_app_assoc_jmeq looks a bit simpler than the previous ones.
Other approaches to vectors
See e.g. this question and this one; I also find this answer very useful too.