简体   繁体   中英

Do native Haskell lists have a “real” type name? Or… what am I doing wrong here?

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.

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. Ie, 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 eg 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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM