Proving uniqueness of an instance of an indexed inductive type
Question
Consider the simple indexed inductive type
Inductive Single : nat -> Set :=
| single_O : Single O
| single_S {n} : Single n -> Single (S n).
Intuitively, I thought that Single n has a unique value for each n : nat. I started by trying to prove that forall s : Single O, s = single_O. However, the usual tactics inversion, destruct, and induction did not work:
s: Single 0s = single_Os: Single 0s = single_Os: Single 0s = single_Os: Single 0s = single_O
The error messages were:
So I resorted to a manual match expression:
s: Single 0single_O = single_Os: Single 0
n: nat
s0: Single nIDProp
Resulting in the following proof context:
which was puzzling, but easy to prove:
reflexivity.s: Single 0single_O = single_Oexact idProp. Qed.s: Single 0
n: nat
s0: Single nIDProp
Questions:
Why was inversion unable to recognize that s could only be single_O and substitute accordingly?
Why did the refine tactic produce the subgoal IDProp?
Is there a way to get inversion or destruct to work in this case? Or, what would a better way to prove s = single_O?
Full example:
Inductive Single : nat -> Set := | single_O : Single O | single_S {n} : Single n -> Single (S n).s: Single 0s = single_Os: Single 0s = single_Os: Single 0s = single_Os: Single 0s = single_Os: Single 0single_O = single_Os: Single 0
n: nat
s0: Single nIDPropreflexivity.s: Single 0single_O = single_Oexact idProp. Qed.s: Single 0
n: nat
s0: Single nIDProp
Answer (gallais)
Or, what would a better way to prove s = single_O?
I would define a function that, given a nat n, computes the canonical proof Single n.
Fixpoint Canonical (n : nat) : Single n :=
match n with
| O => single_O
| S n => single_S (Canonical n)
end.
You can then easily prove that any Single n proof is equal to the canonical one by induction. Here the abstraction won't fail because the equality is already generic over n.
n: nat
s: Single ns = Canonical nn: nat
s: Single ns = Canonical nsingle_O = Canonical 0n: nat
s: Single n
IHs: s = Canonical nsingle_S s = Canonical (S n)reflexivity.single_O = Canonical 0n: nat
s: Single n
IHs: s = Canonical nsingle_S s = Canonical (S n)n: nat
s: Single n
IHs: s = Canonical nsingle_S s = single_S (Canonical n)assumption. Qed.n: nat
s: Single n
IHs: s = Canonical ns = Canonical n
Your original lemma is then a direct corollary.
apply single_canonical with (n := O). Qed.s: Single 0s = single_O
Answer (Meven Lennon-Bertrand)
Regarding IDProp, this is the pattern-matching compilation of Coq at work. Basically, because you scrutinee has a type that can only correspond to the single_O branch, Coq was smart enough to craft a return predicate that gave you an interesting goal only in that branch, the other being replaced by the trivially inhabited IDProp (as you noticed in your proof). So match was smart enough "to recognize that s could only be single_O". If you wish to see what exactly happened, you can use the Show Proof. command.
I'm a bit suprised that destruct, inversion and friends, which are supposed to be built on top of pattern-matching, were not able to succeed where the simpler refine (match …) was. In such cases with complex dependencies, dependent inversion works better than inversion, but it still fails here, sadly.
If you wish to have inversion work here, you'd have to replace single_O by something generic enough. Using gallais' solution, you can do
Fixpoint Canonical (n : nat) : Single n := match n with | O => single_O | S n => single_S (Canonical n) end.s: Single 0s = single_Os: Single 0s = single_Os: Single 0s = Canonical 0reflexivity. Qed.s: Single 0single_O = Canonical 0
Now dependent inversion succeeds because Canonical 0 can successfully be abstracted over 0, while single_O could not.