I want to defined a lenghted list but I like arguments with names at the top of the inductive definition. Whenever I try that I get unification errors with things I hoped worked and was forced to do a definition that obviously has bugs e.g. allows a list where everything is length 0 but has 1 element. How do I fix this?
Inductive Vector {A : Type} (n : nat) : Type :=
| vnil (* not quite right...*)
| vcons (hd : A) (tail: Vector (n-1)).
Check vnil 0.
Check vcons 1 true (vnil 0).
(* Inductive Vector' (n : nat) : Type :=
| vnil': Vector' 0
| vcons': A -> Vector' n -> Vector' (S n). *)
Inductive Vector' {A: Type} : nat -> Type :=
| vnil': Vector' 0
| vcons': forall n : nat, A -> Vector' n -> Vector' (S n).
Check vnil'.
Check vcons' 0 true (vnil').
Inductive Vector'' {A : Type} (n : nat) : Type :=
| vnil'': Vector'' n (* seems weird, wants to unify with n, argh! *)
| vcons'': A -> Vector'' (n-1) -> Vector'' n.
Check vnil'' 0.
Check vcons'' 1 true (vnil'' 0).
(* Check vcons'' 0 true (vnil'' 0). *) (* it also worked! nooooo! hope the -1 did the trick but not *)
Named arguments to the left of
:(they are called parameters) are implicitlyforall'd in each constructor and must appear as the same variable in the return type of each constructor. Arguments to the right (they are called indices) are not implicitlyforall'd and may appear as anything. Part of the issue with your definitions is thatnis already introduced by the time you're writing the type of each constructor, so you can't quite restrict it to beZorS mat that point.The idea is that parameters are supposed to be parameters to the whole inductive definition.
Vector A nandVector B mdo not depend on each other; it would make sense to considerVector AandVector Bto be different inductive definitions, andVectoras a family of inductives parameterized by aType. On the other hand,Vector A (S n)refers toVector A n; you cannot construct the typeVector A (S n)without first constructingVector A n, so they should be considered parts of one inductive constructionVector A : nat -> Type.This interpretation is not strictly enforced—you can poke a hole in it with
Inductive E (n : nat) : Set := | mk_E : E (S n) -> E n.—but the rule about parameters vs. indices in constructor return types is enforced. It is the intent of the design of Coq that the "most natural" way to defineVectorisIf you want to clarify what the
natis doing, you could just leave a comment likeor
If you really want
Inductive Vector (A : Type) (n : nat) : Type, then you have to resort to something likeWhich makes everything messy.