Short version from a Haskell newbie: suppose I have a class Container where the Container has * -> *
kind. I want to put that into another container and still make the second container an instance of the original class like in:
data Container2 a container = Container2 (container a)
instance Container (Conrainer2 a) where ...
But it seems this is not possible as GHC always generates errors like:
Kind mis-match
The first argument of `Container' should have kind `* -> *',
but `Container2 a' has kind `(* -> *) -> *'
Is it possible to workaround that?
Long version: I am toying with the following code modeling an iterator interface in Java:
module Main where
data NextResult a iter = Stop | More a (iter a)
class Iter iter where
next :: iter a -> NextResult a iter
-- Convert iterator to a list
toList :: (Iter c) => c a -> [a]
toList iter = case next iter of
Stop -> []
More value iter2 -> value : toList iter2
-- List itself is iterator
instance Iter [] where
next [] = Stop
next (x:xs) = More x xs
main = let iter = [1,2,3,4,5] in print $ toList iter
With GHC 7.4.1 this compiles and prints the expected 1 2 3 4 5
. Now I want to defined a transforming iterator that constructs a new iterator from a function and an iterator. For that I added the following lines:
data TransformedIter from to iter = TransformedIter (from->to) (iter from)
instance Iter (TransformedIter from to) where
next (TransformedIter f iter) = case next iter of
Stop -> Stop
More value iter2 -> More (f value) (TransformedIter f iter2)
But that generated the error:
Main.hs:21:16:
Kind mis-match
The first argument of `Iter' should have kind `* -> *',
but `TransformedIter from to' has kind `(* -> *) -> *'
In the instance declaration for `Iter (TransformedIter from to)'
I tried to workaround that, but the result was always a type error of one or another kind. So how to model such transformation in Haskell?
Update
I misunderstood how instance declaration works. Based on the suggestion below I flipped the order of TransformedIter types and ended up with:
module Main where
data NextResult a iter = Stop | More a (iter a)
class Iter iter where
next :: iter a -> NextResult a iter
toList :: (Iter c) => c a -> [a]
toList iter = case next iter of
Stop -> []
More value iter2 -> value : toList iter2
instance Iter [] where
next [] = Stop
next (x:xs) = More x xs
main = let iter = [1,2,3,4,5] in print $ toList iter
data TransformedIter iter from to = TransformedIter (from->to) (iter from)
instance Iter (TransformedIter iter from) where
next (TransformedIter f iter) = case next iter of
Stop -> Stop
More value iter2 -> More (f value) (TransformedIter f iter2)
However that produced another error:
Main.hs:22:40:
No instance for (Iter iter)
arising from a use of `next'
In the expression: next iter
In the expression:
case next iter of {
Stop -> Stop
More value iter2 -> More (f value) (TransformedIter f iter2) }
In an equation for `next':
next (TransformedIter f iter)
= case next iter of {
Stop -> Stop
More value iter2 -> More (f value) (TransformedIter f iter2) }
I changed the instance declaration to:
instance Iter (Iter iter => TransformedIter iter from) where
That generated another error:
Main.hs:21:10:
Illegal instance declaration for `Iter
(Iter iter => TransformedIter iter from)'
(All instance types must be of the form (T a1 ... an)
where a1 ... an are *distinct type variables*,
and each type variable appears at most once in the instance head.
Use -XFlexibleInstances if you want to disable this.)
In the instance declaration for `Iter (Iter iter =>
TransformedIter iter from)'
And after I added -XFlexibleInstances I got:
Main.hs:21:10:
Illegal polymorphic or qualified type:
Iter iter => TransformedIter iter from
In the instance declaration for `Iter (Iter iter =>
TransformedIter iter from)'
So I still do not see how to declare TransformedIter to be an instance of Iter. Any clues?
Update 2
Using GADTs GHC extension I managed to define TransformedIter:
module Main where
data NextResult a iter = Stop | More a (iter a)
class Iter iter where
next :: iter a -> NextResult a iter
toList :: (Iter c) => c a -> [a]
toList iter = case next iter of
Stop -> []
More value iter2 -> value : toList iter2
instance Iter [] where
next [] = Stop
next (x:xs) = More x xs
data TransformedIter iter from to where
TransformedIter :: Iter iter =>
(from->to) -> (iter from) -> TransformedIter iter from to
instance Iter (TransformedIter iter from) where
next (TransformedIter f iter) = case next iter of
Stop -> Stop
More value iter2 -> More (f value) (TransformedIter f iter2)
twice = (*) 2
main = let iter = TransformedIter twice [1,2,3,4,5] in print $ toList iter
That compiles and prints the expected 2 4 6 8 10. But is this extension really necessary?
data Container2 container a = Container2 (container a)
. When you haveinstance Iter f
it anticipates that you can writef a
for an iterators over elementsa
, while if you havetype F = TransformedIter from to
thenF a
isn't an iterator over elements ofa
, it's an iterator over elementsto
from the inner iteratora
. – J. AbrahamsonFoldable
. In particular, anyFoldable t
hastoList :: t a -> [a]
which lets you build your iterator. – J. Abrahamsoninstance Iter iter => Iter (TransformedIter iter from) where
: the constraints come first. – J. Abrahamson