基本上我已经定义了一个Tree数据类型,其定义如下:
data Tree a = Empty
| Leaf a
| Node (Tree a) a (Tree a)
deriving (Eq, Ord, Show)
现在我必须创建一个函数来将值插入到有序树中(它不必对树进行排序,只需添加值)。这是我到目前为止所提出的:
insert :: a -> Tree a -> Tree a
insert x Empty = Leaf x
insert x (Leaf m) | m < x = Node (Leaf x) m Empty
| otherwise = Node Empty m (Leaf x)
insert x (Node l m r) | x > m = Node (Leaf l) m (insert x r)
| otherwise = Node (insert x l) m (Leaf r)
但是,当我运行此命令时,我收到以下错误消息:
无法匹配预期类型'a'(刚性变量) 反对推断类型'树a' 'a'受Main.hs:11:10中'insert'类型签名的约束 在'Leaf'的第一个参数中,即'l' 在'Node'的第一个参数中,即'(Leaf l)' 在表达式中:Node(Leaf l)m(insert x r)
我认为这与类型有关,但我看不出哪里放了任何不应该存在的类型。
答案 0 :(得分:10)
你的问题是那个
insert x (Node l m r) | x > m = Node (Leaf l) m (insert x r)
| otherwise = Node (insert x l) m (Leaf r)
应该是
insert x (Node l m r) | x > m = Node l m (insert x r)
| otherwise = Node (insert x l) m r
因为l
和r
已经是树。
答案 1 :(得分:9)
大致从type-checker-ese翻译成英文:
无法匹配预期类型'a'(a 刚性变量)
这意味着它期待一个任意类型a
,它也在其他地方使用(因此“僵硬”),所以它不能只采用任何旧类型。
针对推断类型'Tree a'
这意味着它发现了Tree
包含预期的刚性多态类型的元素。这显然没有意义,所以它抱怨。
'a'受Main.hs:11:10
的'insert'类型签名的约束
这只是表示该类型受到限制,因为您在该类型签名中指定了它。
在'Leaf'的第一个参数中,即'l'在第一个参数中 'Node'的参数,即'(Leaf l)'在表达式中:Node(Leaf l)m(insert x r)
这只是告诉你它正在抱怨哪个特定术语,并带有一些背景。
因此,要解决问题:变量l
是Tree a
,只需要a
的上下文。在这种情况下,l
显然具有正确的类型,因此错误在于如何使用它。为什么类型检查器要查找类型a
?因为您将Tree
数据构造函数应用于它。但等等,l
已经是Tree a
了! et voila ,鳞片从我们的眼睛落下,真相被看到了。
......这只是解释为什么 Edward Kmett 的快速答案是正确的,以及可以用什么样的推理来得出这样的答案的漫长方式。< / p>
答案 2 :(得分:2)
l
是Node
的第一个参数,因此它的类型为Tree a
(整个左子树)。另一方面,Leaf
只取一个值作为参数,而不是整个树。因此Leaf l
给出了类型错误,因为它试图从整棵树中创建一个Leaf。可能你只是想在这个地方l
而不是Leaf l
。
另外,Leaf x
和Node Empty x Empty
之间有什么区别?你确定你需要两个构造函数吗?