Haskell,递归函数"不能构造无限类型"

时间:2014-10-16 18:03:04

标签: haskell recursion

我试图建立一个递归函数来帮助我解决Haskell中的Project Euler problem 15(我对它很新),但编译器告诉我:

 Occurs check: cannot construct the infinite type: t ~ [t]
 Relevant bindings include
   grid :: t (bound at 15.hs:1:22)
   r :: t (bound at 15.hs:1:17)
   d :: t (bound at 15.hs:1:15)
   generateTree :: [t] -> t -> [t] (bound at 15.hs:1:1)
 In the expression: generateTree [d + 1, r] grid
 In the expression:
   [generateTree [d + 1, r] grid, generateTree [d, r + 1] grid]

我不太确定这些问题是什么,而且我遇到编译器以更容易理解的方式抱怨我。这是我的功能:

generateTree (d:r:_) grid
    | down && right = [generateTree [d + 1, r] grid, generateTree [d, r + 1] grid]
    | down = [generateTree [d + 1, r] grid, -1]
    | right = [-1, generateTree [d, r + 1] grid]
    | otherwise = [d, r]
    where down = elem d [0..grid]
          right = elem r [0..grid]

由于

2 个答案:

答案 0 :(得分:3)

您之所以看到错误的原因是您试图说generateTree返回[-1, [-1, [-1, 0]]]之类的值,而[[[-1]], [[-1], [-1, 0]]]没有有效的类型哈斯克尔。列表中的所有值必须具有相同的类型,这意味着列表不能像这样嵌套。你可以像[[[Int]]]一样嵌套它,但是它的类型为data Tree a = Leaf a | Node (Tree a) (Tree a) deriving (Eq, Show) ,这意味着它只能是3级深度。您需要任意嵌套的级别,因此您需要一种定义这种递归结构的新数据类型。

由于您的函数只返回列表中的两个元素,因此您可以使用二叉树执行此操作。幸运的是,这在Haskell中非常简单:

Leaf a

此处Node left right表示单个值,而Node (Leaf (-1)) (Node (Leaf (-1)) (Node (Leaf (-1)) (Leaf 0) ) ) 表示树中的拆分,因此您可以

[-1, [-1, [-1, 0]]]

(为了清晰起见,添加了空格)

这相当于generateTree :: Int -> Int -> Int -> Tree Int generateTree d r grid | down && right = ... | down = ... | right = Node (Leaf (-1)) (generateTree d (r + 1) grid) | otherwise = Node (Leaf d) (Leaf r) where down = d `elem` [0..grid] right = r `elem` [0..grid] 上面的无效列表。这更详细吗?当然,但它允许任意嵌套。

现在您只需修改函数定义即可使用此类型:

{{1}}

我将让你完成定义的其余部分,这只是一个让你入门的例子。

答案 1 :(得分:1)

您的generateTree函数返回一个列表,请参阅:

| otherwise = [d, r]

但是dr的类型是什么? generateTree返回generateTree函数返回的列表(列表中的所有元素必须是同一类型):

| right = [-1, generateTree [d, r + 1] grid]

换句话说,你的逻辑被打破了。学习类型系统,学会编写类型然后错误就会变得明显。