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:
Lemma emptyIsAlwaysNil : 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:
Abstracting over the terms "0" and "a" leads to a term
fun (n : nat) (a0 : bits n) => a0 = bitsNil
which is ill-typed.
Reason is: Illegal application:
The term "@eq" of type "forall A : Type, A -> A -> Prop"
cannot be applied to the terms
"bits n" : "Set"
"a0" : "bits n"
"bitsNil" : "bits 0"
The 3rd term has type "bits 0" which should be coercible to
"bits n".
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?
Proof (a) Suppose that 0 and 0 are both zero vectors in V . Then x + 0 = x and x + 0 = x, for all x ∈ V . Therefore, 0 = 0 + 0, as 0 is a zero vector, = 0 + 0 , by commutativity, = 0, as 0 is a zero vector. Hence, 0 = 0 , showing that the zero vector is unique.
We define a vector as an object with a length and a direction. However, there is one important exception to vectors having a direction: the zero vector, i.e., the unique vector having zero length. With no length, the zero vector is not pointing in any particular direction, so it has an undefined direction.
A zero vector, denoted. , is a vector of length 0, and thus has all components equal to zero. It is the additive identity of the additive group of vectors.
Trivial or zero vector spaceA basis for this vector space is the empty set, so that {0} is the 0-dimensional vector space over F. Every vector space over F contains a subspace isomorphic to this one.
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).
Lemma emptyIsAlwaysNil_general :
forall n (H: n = 0) {a: bits n},
rew [bits] H in a = bitsNil.
Proof.
intros.
induction a; simpl.
(* bitsNil *)
rewrite <- eq_rect_eq_dec; auto.
apply PeanoNat.Nat.eq_dec.
(* bitsCons - derive a contradiction *)
exfalso; discriminate H.
Qed.
Lemma emptyIsAlwaysNil : forall {a: bits 0},
a = bitsNil.
Proof.
intros.
change a with (rew [bits] eq_refl in a).
apply emptyIsAlwaysNil_general.
Qed.
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).
Lemma emptyIsAlwaysNil :
forall {a: bits 0}, a = bitsNil.
Proof.
intros.
dependent destruction a; reflexivity.
Qed.
Print Assumptions emptyIsAlwaysNil.
(* Axioms:
JMeq_eq : forall (A : Type) (x y : A), x ~= y -> x = y *)
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:
Print emptyIsAlwaysNil.
emptyIsAlwaysNil =
fun a : bits 0 =>
match
a as a0 in (bits n)
return
(match n as x return (bits x -> Type) with
| 0 => fun a1 : bits 0 => a1 = bitsNil
| S n0 => fun _ : bits (S n0) => IDProp
end a0)
with
| bitsNil => eq_refl
| bitsCons _ _ => idProp
end
: forall a : bits 0, a = bitsNil
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With