有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

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) 个答案

  1. # 1 楼答案

    iterator :: Iterator it => i e -> it e
    

    这意味着调用者可以选择it成为他们想要的任何东西,只要它实现Iterator。另一种看待它的方式是,它是iterator对实现Iterator的所有类型it的承诺

    无论调用者要求什么,您的实现都会提供一个LinkedListIterator

    编译器无法证明它们是相同的东西(因为调用者可能需要不同的Iterator实现),因此会发出错误

    这与Java不同,在Java中,调用者选择输入的类,被调用者选择输出的类。在Haskell中,调用者选择输入的类型和输出的类型

    ~表示类型相等


    一些更广泛的观点。(我很感激您尝试将Java习语翻译成Haskell,但在我看来,您需要学习Haskell习语。)

    1. 有时候你不想返回一个实现typeclass的值,你只想返回一个值

      如果Iterator不是一个类型类,而是一个数据类型

      data Iterator e = Iterator {next    :: (Iterator e, e),
                                  hasNext :: Bool}
      

      。。。然后,您可以只返回类型为Iterator的值,而不必担心不同的类型类实现

      惰性意味着迭代器中的连续值在被请求之前不会生成(也不会抛出异常)。只要不使用旧的迭代器值,这些值可以在迭代过程中被垃圾收集,所以我们仍然使用常量空间

    2. 更好的Iterator定义是

      data Iterator e = Iterator {next :: Maybe (Iterator e, e)}
      

      这是更好的,因为它使您更难在不首先检查是否存在下一个值的情况下从迭代器中请求下一个值

    3. 我对Iterator的第二个定义看起来有点像你对LinkedList的定义,也像标准Haskell列表(它们本身就是链表)的定义。实际上,在迭代需要的地方,使用Haskell列表作为中间数据结构是惯用的

    4. 阅读Typeclassopedia中的^{}^{}类型类。事实上,这是对一些听起来更可怕的类型类的一个很好的介绍