Suppose I define my own list type.
data MyVec : Nat -> Type -> Type where
MyNil : MyVec Z a
(::) : a -> MyVec k a -> MyVec (S k) a
And a myMap function serving as fmap for MyVec:
myMap : (a -> b) -> MyVec k a -> MyVec k b
myMap f MyNil = ?rhs_nil
myMap f (x :: xs) = ?rhs_cons
Attempting to solve the ?rhs_nil hole in my mind:
:t ?rhs_nilisMyVec 0 b- fair enough - I need a constructor that returns
MyVecparameterized byband I needkto be0(orZ) and I can see thatMyNilis indexed byZand parameterized by whatever, so I can usebeasily, therefore?rhs_nil=MyNiland it typechecks, dandy :t ?rhs_consisMyVec (S k)- I need a constructor that returns
MyVecparameterized byband I needkto be(S k)
I do see that the constructor (::) constructs a list indexed by (S k) and I try to use it. The first argument needs to be of type b considering I am building a MyVec <> b and the only way to get it is to apply x to f.
myMap f (x :: xs) = f x :: <>
Now I get confused. The RHS of (::) is supposed to be MyVec k b, why can I not simply use the MyNil constructor, with unification / substitution k == Z (that MyNil) gives me, getting:
myMap f (x :: xs) = f x :: MyNil
I do understand that I need to recurse and have = f x :: myMap f xs, but how does the compiler know the number of times the (::) constructor needs to be applied? How does it infer the correct k for this case, preventing me from using Z there.