我正在做一个有趣的项目,我正在尝试从Java重做一些基本数据类型和概念。目前我正在处理迭代器。
我的方法如下: (1)将接口转换为类型类 (2)为实际实现声明自定义数据类型和实例
所以我创建了以下类型类:
class Iterator it where
next :: it e -> (it e, e)
hasNext :: it e -> Bool
class Iterable i where
iterator :: Iterator it => i e -> it e
class Iterable c => Collection c where
add :: c e -> e -> c e
是的,我正在尝试翻译迭代器的概念(在这种情况下,它只是一个围绕实际列表的框)。
这是我对简单列表的实现:
data LinkedList e = Element e (LinkedList e) | Nil
deriving (Show, Eq)
instance Collection LinkedList where
add Nil e = Element e Nil
add (Element x xs) e = Element x $ add xs e
我已经排除了其他功能,例如remove,contains,addAll以简化。
这是迭代器:
data LinkedListIterator e = It (LinkedList e)
instance Iterator LinkedListIterator where
hasNext (It Nil) = False
hasNext (It _) = True
next (It (Element x xs)) = (It xs, x)
最后,缺少Iterable LinkedList的实例。这就是我的工作:
instance Iterable LinkedList where
iterator list = It list
迭代器函数将列表包装到LinkedListIterator
并返回。 GHC声称这是一个错误:
Could not deduce (it ~ LinkedListIterator)
from the context (Iterator it)
bound by the type signature for
iterator :: Iterator it => LinkedList e -> it e
`it' is a rigid type variable bound by
the type signature for
iterator :: Iterator it => LinkedList e -> it e
Expected type: it e
Actual type: LinkedListIterator e
我不太明白。 LinkedListIterator有一个Iterator实例,为什么预期的Type“it e”与实际类型“LinkedListIterator e”不兼容(据我所知,是 Iterator e) 。无论如何,波浪号(~
)意味着什么?什么是刚性类型变量?
编辑:我将标题从Translating Java Types into Haskell types: type deduction fail due to rigid type variable
更改为Returning something from another type class B in function of type class A in Haskell
,因为我认为我的实际问题与返回类型-B类有关-from-type-class-A-issue in iterator-function。
解决方案:由于答案,我现在将代码更改为以下版本。但是,我很开心阅读Typeclassopedia并且只能推荐它。如上所述,人们应该学习哈希尔的习语。
data Iterator c e = Next (Iterator c e, e) | Empty
deriving (Show, Eq)
next :: Iterator c e -> (Iterator c e, e)
next (Next (i, e)) = (i, e)
hasNext :: Iterator c e -> Bool
hasNext Empty = False
hasNext _ = True
class Iterable i where
iterator :: i e -> Iterator (i e) e
instance Iterable LinkedList where
iterator Nil = Empty
iterator (Element x xs) = Next (iterator xs, x)
答案 0 :(得分:8)
iterator :: Iterator it => i e -> it e
这意味着来电者可以选择it
为他们想要的任何内容,但要实施Iterator
。查看它的另一种方式是iterator
的承诺适用于实现it
的所有类型Iterator
。
无论调用者要求什么,您的实现都会提供LinkedListIterator
。
编译器无法证明它们是相同的(因为调用者可能需要不同的Iterator
实现),因此发出错误。
这与Java不同,其中调用者选择输入的类,并且被调用者选择输出的类。在Haskell中,调用者选择输入的类型和输出。
~
表示类型相等。
一些更广泛的观点。 (我感谢您尝试将Java习语翻译成Haskell,但是您需要学习Haskell习语。)
有时您不想返回实现类型类的值,您只想返回一个值。
如果不是Iterator
是类型类,那么它是一种数据类型......
data Iterator e = Iterator {next :: (Iterator e, e),
hasNext :: Bool}
...然后您可以返回类型Iterator
的值,而不必担心不同的类型类实现。
Laziness意味着在被要求之前,不会生成迭代器的连续值(并且不会抛出异常)。只要您没有使用旧的迭代器值,这些值就可以在迭代时进行垃圾收集,因此我们仍然使用常量空间。
Iterator
的更好定义是
data Iterator e = Iterator {next :: Maybe (Iterator e, e)}
这样做更好,因为在没有先检查是否存在下一个值的情况下,您更难从迭代器中请求下一个值。
我对Iterator
的第二个定义看起来有点像LinkedList
的定义,也像标准Haskell列表(它们本身是链表)的定义一样。事实上,将Haskell列表用作迭代所需的中间数据结构是不恰当的。
了解Typeclassopedia中的Foldable
和Traversable
类型类。事实上,read the Typeclassopedia,它是对一些更可怕的类型类别的一个很好的介绍。