来自Haskell新手的简短版本:假设我有一个Container容器,其中Container有* -> *
种类。我希望把他们到另一个容器中,仍然使第二容器的原始类的实例像:Haskell - 容器和实例declration的容器
data Container2 a container = Container2 (container a)
instance Container (Conrainer2 a) where ...
但看来这是不可能的,因为GHC总是产生类似的错误:
Kind mis-match
The first argument of `Container' should have kind `* -> *',
but `Container2 a' has kind `(* -> *) -> *'
是否可以解决这个问题?
长版:我用下面的代码建模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
随着GHC 7.4.1本编译并打印预期1 2 3 4 5
。现在我想定义一个从函数和迭代器构造新迭代器的变换迭代器。对于我添加了以下几行:
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)
但生成该错误:
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)'
我想变通方法,但结果总是一种或另一种类型错误。那么如何在Haskell中对这种转换进行建模呢?
更新
我误解了实例声明的工作原理。根据该建议,下面我翻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
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)
但是所产生另一个错误:
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) }
我改变了实例声明:
instance Iter (Iter iter => TransformedIter iter from) where
这产生了另一个错误:
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)'
我加-XFlexibleInstances
后,我得到了:
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)'
所以我还没有看到如何声明TransformedIter是Iter项目的一个实例。任何线索?
更新2
使用GADTs GHC扩展我设法确定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
,编译并打印预期的2 4 6 8 10,但确实需要这种扩展?
只需翻转像'data Container2 container a = Container2(container a)'这样的参数即可。当你有'instance Iter f'时,它预计你可以为元素'a'的迭代器写'fa',而如果你有'type F = TransformedIter from',那么'F a'不是元素的迭代器的'a',它是内部迭代器'a'的元素'to'的迭代器。 –
另外,这个类在Haskell中已经存在为'Foldable'。特别是,任何'Foldable t'都有'toList :: t a - > [a]',它可以让你构建你的迭代器。 –
谢谢@J。 Abrahamson,我明白类型排序有什么问题。但是现在我又遇到了另一个错误,请参阅更新后的版本。 –