java从Haskell中类型类A的函数中的另一个类型类B返回某些内容
我正在做一个有趣的项目,其中我试图从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有一个迭代器实例,那么为什么预期的类型“it e”与实际的类型“LinkedListIterator e”不兼容(据我所知,是一个迭代器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
,因为我认为我的实际问题与迭代器函数中的返回-something-of-type-class-B-from-type-class-A-issue有关
解决方案:多亏了这些答案,我现在将代码更改为以下版本。然而,我在阅读Typeclassopedia时玩得很开心,只能推荐它。如前所述,一个人应该学习haskell习语
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)
# 1 楼答案
这意味着调用者可以选择
it
成为他们想要的任何东西,只要它实现Iterator
。另一种看待它的方式是,它是iterator
对实现Iterator
的所有类型it
的承诺无论调用者要求什么,您的实现都会提供一个
LinkedListIterator
编译器无法证明它们是相同的东西(因为调用者可能需要不同的
Iterator
实现),因此会发出错误这与Java不同,在Java中,调用者选择输入的类,被调用者选择输出的类。在Haskell中,调用者选择输入的类型和输出的类型
~
表示类型相等一些更广泛的观点。(我很感激您尝试将Java习语翻译成Haskell,但在我看来,您需要学习Haskell习语。)
有时候你不想返回一个实现typeclass的值,你只想返回一个值
如果
Iterator
不是一个类型类,而是一个数据类型。。。然后,您可以只返回类型为
Iterator
的值,而不必担心不同的类型类实现惰性意味着迭代器中的连续值在被请求之前不会生成(也不会抛出异常)。只要不使用旧的迭代器值,这些值可以在迭代过程中被垃圾收集,所以我们仍然使用常量空间
更好的
Iterator
定义是这是更好的,因为它使您更难在不首先检查是否存在下一个值的情况下从迭代器中请求下一个值
我对
Iterator
的第二个定义看起来有点像你对LinkedList
的定义,也像标准Haskell列表(它们本身就是链表)的定义。实际上,在迭代需要的地方,使用Haskell列表作为中间数据结构是惯用的阅读Typeclassopedia中的^{} 和^{} 类型类。事实上,这是对一些听起来更可怕的类型类的一个很好的介绍