使用 "toList" 函数创建自定义列表数据结构
Create custom list data structure with "toList" function
我想创建自己的名为节点的列表数据结构。然后我将使用我的 ListConverter class,它包含 'toList' 函数,并创建它的一个实例。
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 告诉我,预期的类型是 'Integer' 但目前是 'a'。我很困惑,因为在这个例子中我给出了一个类型(整数)。这是错误消息:
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]
| ^
您的 ListConverter 实例应接受任何 class Integral for "a" 的值,但 Integer 是特定类型,而不是 class;你必须这样做:
instance ListConverter (Nodes Integer) where
或者相反,使您的 ListConverter class 能够生成您的节点值包含的任何类型的列表:
class ListConverter f where
toList :: f a -> [a]
instance ListConverter Nodes where
toList Empty = []
toList (Node x y) = x : toList y
(toList 的第二个等式 - (Node x Empty) - 是不必要的)
这个实例的问题很简单。您已提供签名:
toList :: a -> [Integer]
但您尝试的实例实际上具有类型 Nodes a -> [a]
。这不起作用,除非 a
是 Integer
类型 - 但您声称它适用于所有 Integral a
。这包括其他类型,例如 Int
.
一个解决方案就是限制您的实例:
instance ListConverter (Nodes Integer) where...
这会起作用 - 但在我看来并没有真正尊重您可能希望 class 实现的精神。
我认为最好的解决方案是认识到列表和您的 Nodes
类型都是由另一种类型参数化的,并定义 class 以便在通用类型上进行转换基地class。这听起来比实际更复杂,我的意思是:
class ListConverter l where
toList :: l a -> [a]
然后你可以写一个instance ListConverter Nodes where...
,然后只复制你现有的toList
定义。 (我顺便指出,中间那条线是多余的。)
我想创建自己的名为节点的列表数据结构。然后我将使用我的 ListConverter class,它包含 'toList' 函数,并创建它的一个实例。
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 告诉我,预期的类型是 'Integer' 但目前是 'a'。我很困惑,因为在这个例子中我给出了一个类型(整数)。这是错误消息:
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]
| ^
您的 ListConverter 实例应接受任何 class Integral for "a" 的值,但 Integer 是特定类型,而不是 class;你必须这样做:
instance ListConverter (Nodes Integer) where
或者相反,使您的 ListConverter class 能够生成您的节点值包含的任何类型的列表:
class ListConverter f where
toList :: f a -> [a]
instance ListConverter Nodes where
toList Empty = []
toList (Node x y) = x : toList y
(toList 的第二个等式 - (Node x Empty) - 是不必要的)
这个实例的问题很简单。您已提供签名:
toList :: a -> [Integer]
但您尝试的实例实际上具有类型 Nodes a -> [a]
。这不起作用,除非 a
是 Integer
类型 - 但您声称它适用于所有 Integral a
。这包括其他类型,例如 Int
.
一个解决方案就是限制您的实例:
instance ListConverter (Nodes Integer) where...
这会起作用 - 但在我看来并没有真正尊重您可能希望 class 实现的精神。
我认为最好的解决方案是认识到列表和您的 Nodes
类型都是由另一种类型参数化的,并定义 class 以便在通用类型上进行转换基地class。这听起来比实际更复杂,我的意思是:
class ListConverter l where
toList :: l a -> [a]
然后你可以写一个instance ListConverter Nodes where...
,然后只复制你现有的toList
定义。 (我顺便指出,中间那条线是多余的。)