使用“ toList”功能创建自定义列表数据结构

时间:2019-05-29 23:23:20

标签: haskell types instance

我想创建自己的名为Nodes的列表数据结构。然后,我将使用包含“ toList”功能的ListConverter类,并创建其实例。

data Nodes a = Empty
             | Node a (Nodes a)

class ListConverter a where
    toList :: a -> [Integer]

instance (Integral a) => ListConverter (Nodes a) where
    toList Empty = []
    toList (Node x Empty) = [x]
    toList (Node x y) = x : toList y

GHCi告诉我,期望的类型为“整数”,但当前为“ a”。我非常困惑,因为在这种情况下,我为(Integral)提供了一个类型。这是错误消息:

error:
    * Couldn't match expected type `Integer' with actual type `a'
      `a' is a rigid type variable bound by
        the instance declaration
        at main.hs:7:10-48
    * In the expression: x
      In the expression: [x]
      In an equation for `toList': toList (Node x Empty) = [x]
    * Relevant bindings include
        x :: a (bound at main.hs:9:18)
        toList :: Nodes a -> [Integer] (bound at main.hs:8:5)
  |
9 |     toList (Node x Empty) = [x]
  |                              ^

2 个答案:

答案 0 :(得分:4)

您的ListConverter实例应接受“ a”的类Integral的任何值,但是Integer是特定类型,而不是类。您必须这样做:

index.html

或者相反,使您的ListConverter类能够生成Nodes值包含的任何类型的列表:

document.addEventListener('DOMContentLoaded', function() {
    M.AutoInit();
 });

(toList的第二个等式-(节点x空)-是不必要的)

答案 1 :(得分:1)

此实例的问题非常简单。您已签名:

toList :: a -> [Integer]

但是您尝试的实例实际上具有类型Nodes a -> [a]。除非aInteger类型,否则这是行不通的-但是您已经宣称它适用于所有Integral a。其中包括其他类型,例如Int

一种解决方案就是限制您的实例:

instance ListConverter (Nodes Integer) where...

这是可行的-但我认为并没有真正尊重您可能打算上课的精神。

我认为最好的解决方案是认识到列表和您的Nodes类型都被另一种类型所参数化,并以在通用基类上进行转换的方式定义该类。听起来比实际要复杂,

class ListConverter l where
    toList :: l a -> [a]

然后,您可以编写instance ListConverter Nodes where...,只需复制现有的toList定义。 (我要指出的是,中间的一行是多余的。)