为什么是无限类型? (进行检查:无法构造无限类型:a〜树a)

时间:2020-07-11 21:46:26

标签: haskell types infinite

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中会发生错误。为什么?

1 个答案:

答案 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的值。因此,它们具有不同的类型:aTree 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

相关问题