Haskell beginner here. I've defined the following types:
data Nat = Z | S Nat
data Vector a n where
Nil :: Vector a Z
(:-) :: a -> Vector a n -> Vector a (S n)
infixl 5 :-
I'm trying to write the function, takeWhileVector which behaves the same as takeWhile does on lists, but on Vectors.
My implementation is as follows:
takeWhileVector :: (a -> Bool) -> Vector a n -> Vector a m
takeWhileVector f Nil = Nil
takeWhileVector f (x :- xs) = if (f x) then (x :- takeWhileVector f xs) else Nil
This doesn't compile and produces the following error:
Could not deduce (m ~ 'S n0)
from the context (n ~ 'S n1)
bound by a pattern with constructor
:- :: forall a (n :: Nat). a -> Vector a n -> Vector a ('S n),
in an equation for ‘takeWhileVector’
at takeWhileVector.hs:69:20-26
‘m’ is a rigid type variable bound by
the type signature for
takeWhileVector :: (a -> Bool) -> Vector a n -> Vector a m
at takeWhileVector.hs:67:20
Expected type: Vector a m
Actual type: Vector a ('S n0)
Relevant bindings include
takeWhileVector :: (a -> Bool) -> Vector a n -> Vector a m
(bound at takeWhileVector.hs:69:1)
In the expression: (x :- takeWhileVector f xs)
In an equation for ‘takeWhileVector’:
takeWhileVector f (x :- xs) = (x :- takeWhileVector f xs)
I would have thought that my type definition for takeWhileVector says the following:
For all types 'a' and 'n's of kind Nat, this function returns a 'Vector a m', where 'm' is kind Nat.
Do I need to change the type signature of takeWhileVector to be more specific so that it shows that the result is Vector a (m :: Nat)? Otherwise, how can I change this to have it compile?
The type you suggest can not be implemented, i.e. it is not inhabited:
Remember that the caller chooses the type variables
a,n,m
. This means that the caller can use your function as e.g.which is nonsense, since you can't produce some
a
s if you got none at the beginning. Even more practically, the caller of this function is not meant to be able to choose how many results to have and pass a completely unrelated function -- that would disagree with the intended semantics oftakeWhile
.I guess what you really mean is something like
except that
exists
is not valid Haskell syntax. Instead, you need something like