发生检查:无法构造无限类型:a = [a]

时间:2011-04-03 11:35:16

标签: haskell

我一直在尝试在haskell中执行2nd Project Euler problem但我已经得到了:Occurs check: cannot construct the infinite type: a = [a]

fibonacci 0 _ = 0
fibonacci 1 _ = 1
fibonacci x xs = (xs!!(x-2)) + (xs!!(x-1))

fibonaccisLessThan = takeWhile(<40) $ foldr fibonacci [] [0..]

sumOfEvenFibonaccis = sum $ filter even $ fibonaccisLessThan

main = putStrLn $ show $ sumOfEvenFibonaccis

有人可以告诉我为什么吗?

5 个答案:

答案 0 :(得分:8)

考虑第一到第五行。你想达到什么目的?你想获得一份懒惰的Fibonaccis列表。但你的方法很奇怪。我没看透你的代码,但我想我对你尝试做的事情有所了解。尝试给你的函数类型签名,然后你会很快看到,出了什么问题。

这是一个更短的方式:

考虑缩短你的方法。让我们尝试定义一个懒惰的Fibonacci数列表:

fibs = undefined

那么,现在呢?我们知道的第一件事是前两个元素是0和1:

fibs = 0 : 1 : undefined

其余的? fibs添加了fibs的移位版本。看这个。 zipWith f使用函数f将列表与另一个列表组合在一起:

fibs = 0 : 1 : zipWith (+) fibs (tail fibs)

我们在这里。就是这样。

答案 1 :(得分:8)

您的错误消息的原因是函数fibonacci返回一个数字,然而,您在第5行使用它,就像它将返回相同类型的数字列表一样。

这会导致类型检查器尝试将类型为“[a]”的类型“a”统一起来,这就会出现检查错误。

想一想:你的程序中实际构建的列表在哪里?你知道,应该有一个:运算符直接或间接应用于某处,但事实并非如此。因此,在你的程序中,斐波纳契数列表完全是虚构的。

答案 2 :(得分:3)

首先让我们注意斐波纳契的类型为Int -> [Int] -> Int,而且该折叠器的类型为(a -> b -> b) -> b -> [a] -> b,因此我们无法将斐波那契赋予折叠,因为我们无法统一a-> b-> bInt -> [Int] -> Int。这是错误消息的来源。

要修复它,我们必须改变斐波纳契函数。 fibonacci = 0 : 1 : zipWith (+) fibonacci (tail fibonacci)是经典的haskell方式,有更多方法可以查看this haskellwiki page。然后你所要做的就是:

sumOfEvenLessThen n = sum . filter even . takeWhile (<n)
main = print $ sumOfEvenLessThen 40 fibonacci

答案 3 :(得分:3)

一些一般性建议:如果出现奇怪的类型错误,请确保在所有顶级定义上都有类型签名。这可确保在正确的定义中报告您的类型错误。 也就是说,你的斐波纳契定义很奇怪。

答案 4 :(得分:1)

其他答案已经指出了错误的来源,并展示了Haskell中Fibonacci数字的非常紧凑和优雅的“标准”定义。这是定义它的另一种方式,它可能更适合初学者:

fibs = map fst $ iterate next (0,1) where 
    next (x,y) = (y,x+y)

这个想法不仅要跟踪最后一个,而且要跟踪最后一个两个 Fibonacci数字,这可以使用对来完成。通过这个技巧,可以很容易地定义递归关系。

我们从参数(0,1)开始,并使用next函数重新生成此起始值的列表:[(0,1),(1,1),(1,2),(2,3),(3,5)...]。那么剩下要做的就是“抛弃”对的第二个参数,由map fst $ ...完成。

<强> [更新]

另一个不错的定义(类似于zipWith-Version的工作方式)是:

fibs = 0 : scanl (+) 1 fibs