data Tree a = Branch a a | Leaf deriving (Show)
construct :: (Integral a) => [a] -> Tree a
construct [] = Leaf
construct (x:[]) = Leaf -- _____error________
construct (l:r:xs) = if l>r then Branch l (construct $ r:xs)
else Branch (construct $ l:xs) r
* Occurs check: cannot construct the infinite type: a ~ Tree a
* In the second argument of `Branch', namely `(construct $ r : xs)'
In the expression: Branch l (construct $ r : xs)
In the expression:
if l > r then
Branch l (construct $ r : xs)
else
Branch (construct $ l : xs) r
* Relevant bindings include
xs :: [a] (bound at C:\Stuff\code\New folder (2)\try.hs:69:16)
r :: a (bound at C:\Stuff\code\New folder (2)\try.hs:69:14)
l :: a (bound at C:\Stuff\code\New folder (2)\try.hs:69:12)
construct :: [a] -> Tree a
为什么它是无限类型?这种“无限类型”是输入还是输出?
并且,如果我将construct (x:[]) = Leaf
更改为construct (x:[]) = x
,则该x
中会发生错误。为什么?
答案 0 :(得分:7)
让我们从头开始:
data Tree a = Branch a a | Leaf deriving(Show)
根据定义,该“树”将仅包含两个a
值(在Branch
中)或根本不包含任何值(Leaf
)。我不确定为什么将其称为树。看来这不是您要执行的操作。也许你想要
data Tree a = Branch (Tree a) (Tree a) | Leaf a deriving(Show)
这是一棵叶子上具有a
值的树。或者,或者,
data Tree a = Branch a (Tree a) (Tree a) | Leaf deriving(Show)
这是内部节点中具有a
值的树。
无论如何,让我们解决您的问题:
construct :: (Integral a) => [a] -> Tree a
construct (l:r:xs) = if l>r then Branch l (construct $ r:xs) else ...
在这里,l
的类型为a
。同样,construct $ r:xs
产生类型为Tree a
的值。因此,它们具有不同的类型:a
与Tree a
。
然后,您将这两个值传递给Branch
,根据定义,它们描述两个相同类型的值。编译器尝试解决类型相等性
a ~ Tree a
但是这立即失败了,因为唯一的解决方案就是不存在的无限类型
a = Tree (Tree (Tree ...))
最后,要修复代码,您将需要修改树类型,以使其实际上是树。之后,您需要将construct
代码修改为新的类型。
如果我将
construct (x:[]) = Leaf
更改为construct (x:[]) = x
,则该x
中会发生错误。为什么?
因为x
的类型为a
,但是construct
的签名保证了Tree a
,因此与前面的情况一样要求a ~ Tree a
。