Reputation: 11885
Following the article about Haskell type families, I found the courage to try it myself. Well knowing that Lists are already Applicative and whatnot, just to see if I got the ideas right, I tried to do the following:
{-# LANGUAGE TypeFamilies #-}
class Iterable c where
data Iterator c :: * -> *
current :: Iterator c a -> Maybe a
next :: Iterator c a -> Maybe (Iterator c a)
instance Iterable [] where
data Iterator [] a = ListIterator [a] -- Problem in this line!
current (ListIterator []) = Nothing
current (ListIterator (x:xs)) = Just x
next (ListIterator []) = Nothing
next (ListIterator (x:xs)) = Just (ListIterator xs)
This is in analogy of the example code given in the above haskell tutorial.
What this is supposed to do is, to implement the type family Iterable
for native Haskell lists, generically.
I tried alternatively to write data Iterator [a] = ListIterator [a]
but this yields the same error message as the code I show here:
temp.hs:8:19: error:
* Expecting one more argument to `[]'
Expected a type, but `[]' has kind `* -> *'
* In the first argument of `Iterable', namely `[]'
In the instance declaration for `Iterable []'
Hence, my question, if I have an option to use the real type name for lists instead of []
, as I suspect, this is where my (syntactical?) problem is coming from.
Upvotes: 1
Views: 99
Reputation: 120711
Note that the class does not really use its argument in any way at all, it only uses Iterator c
but not c
itself. That's ok in principle – c
works basically just as a tag, to select some other type – though you should ask yourself whether that's really what you want and if a more direct approach wouldn't be better.
The only real problem: because c
isn't used by itself, the compiler has no way of knowing what kind this should have. I.e., basically your class is polymorphically kinded, which Haskell98 doesn't allow... hence it defaults to the simplest possible kind, namely *
. GHCi can tell you this:
*Main> :k Iterable
Iterable :: * -> Constraint
So that would work for e.g. instance Iterable Int
, because Int
has kind *
. But []
doesn't, it has kind * -> *
. Hence that error message.
You can enable GHC's PolyKinds
extension to avoid this defaulting:
{-# LANGUAGE PolyKinds #-}
class Iterable c where
data Iterator c :: * -> *
current :: Iterator c a -> Maybe a
next :: Iterator c a -> Maybe (Iterator c a)
Now it is
*Main> :k Iterable
Iterable :: k -> Constraint
and therefore both instance Iterable Int
will work (with k ~ *
) and instance Iterable []
too (with k ~ (* -> *)
).
Alternatively, you could manually state that c
should always have kind * -> *
:
{-# LANGUAGE KindSignatures #-}
class Iterable (c :: * -> *) where
data Iterator c :: * -> *
current :: Iterator c a -> Maybe a
next :: Iterator c a -> Maybe (Iterator c a)
Now instance Iterable []
would work, but instance Iterable Int
wouldn't.
Upvotes: 5