Prove that the only zero-length vector is nil
Question
I have a type defined as
Inductive bits : nat -> Set :=
| bitsNil : bits 0
| bitsCons : forall {l}, bool -> bits l -> bits (S l).
and I'm trying to prove:
forall a : bits 0, a = bitsNil
After intros, I've tried constructor 1, case a, intuition, to no avail. case a seems like the closest, but it gets an error:
It sounds like it can't determine whether a bit-vector of an arbitrary length is equal to one of zero-length, because they're different at the type level. Is that correct?
Answer (Tej Chajed)
Yes, you're basically correct: specifically, what isn't type checking is Coq's attempt to construct a match on a:bits 0 (which is what case does): the bitsCons case has an ill-typed conclusion.
Here's an axiom-free proof. The key idea is to manually generalize the statement to any n = 0 (I couldn't figure out how to do this with tactics; they all trip up on the dependency). The equality proof then makes the conclusion type check regardless of what n is, and we can dismiss the bitsCons case because we'll have n = S n'. In the more difficult bitsNil case, we make use of eq_rect_eq_dec, which is a consequence of Axiom K but is provable when the type index (nat, in this case) has decidable equality. See the Coq standard library documentation for some other things you can do without axioms with decidable equality.
Require PeanoNat. Require Import Eqdep_dec. Import EqNotations. Inductive bits : nat -> Set := | bitsNil : bits 0 | bitsCons : forall {l}, bool -> bits l -> bits (S l).forall (n : nat) (H : n = 0) (a : bits n), rew [bits] H in a = bitsNilforall (n : nat) (H : n = 0) (a : bits n), rew [bits] H in a = bitsNiln: nat
H: n = 0
a: bits nrew [bits] H in a = bitsNilH: 0 = 0rew [bits] H in bitsNil = bitsNill: nat
H: S l = 0
b: bool
a: bits l
IHa: forall H : l = 0, rew [bits] H in a = bitsNilrew [bits] H in bitsCons b a = bitsNilH: 0 = 0rew [bits] H in bitsNil = bitsNilH: 0 = 0bitsNil = bitsNilH: 0 = 0forall x y : nat, {x = y} + {x <> y}apply PeanoNat.Nat.eq_dec.H: 0 = 0forall x y : nat, {x = y} + {x <> y}exfalso; discriminate H. Qed.l: nat
H: S l = 0
b: bool
a: bits l
IHa: forall H : l = 0, rew [bits] H in a = bitsNilrew [bits] H in bitsCons b a = bitsNilforall a : bits 0, a = bitsNilforall a : bits 0, a = bitsNila: bits 0a = bitsNilapply emptyIsAlwaysNil_general. Qed.a: bits 0rew [bits] eq_refl in a = bitsNil
You don't need the rew H in x notation from EqNotations (it just wraps eq_rect, the equality recursion principle), but I find it makes things much more readable.
However, you can prove this theorem more simply if you're willing to use an axiom, specifically JMeq_eq (see CPDT's equality chapter for more details), since then you can use dependent induction or dependent destruction:
Require Import Program.Equality. Inductive bits : nat -> Set := | bitsNil : bits 0 | bitsCons : forall {l}, bool -> bits l -> bits (S l).forall a : bits 0, a = bitsNilforall a : bits 0, a = bitsNildependent destruction a; reflexivity. Qed.a: bits 0a = bitsNil
Answer (Anton Trunov)
Here is a simple proof (borrowed from this Coq Club thread):
Definition emptyIsAlwaysNil {a: bits 0} : a = bitsNil := match a with bitsNil => eq_refl end. Opaque emptyIsAlwaysNil.
Here is what Coq builds under the hood:
A: Reminds me of Monin's small inversions: hal.archives-ouvertes.fr/inria-00489412