我一直在尝试在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
有人可以告诉我为什么吗?
答案 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-> b
与Int -> [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