2011-04-03 32 views
4

我一直试图做的Haskell中2nd Project Euler problem,但我已经得到:Occurs check: cannot construct the infinite type: a = [a]出现,请检查:无法构造无限类型: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 

有人能告诉我为什么吗?

+1

如果你能给错误的路线,那将是很好的。作为一个侧面说明,当你有多个'$'时,你通常希望使用合成来优雅。 – alternative 2011-04-03 11:41:14

回答

9

想想第一至第五行。你想实现什么?你想得到一个懒惰的斐波那契列表。但是你的方法很奇怪。我没有看到你的代码,但我想我对你想做的事有一个想法。尝试给你的函数类型签名,然后你会看到很快,出了什么问题。

这里是一个简短的形式:

的短切你的方法思考。让我们试着定义一个斐波那契数列的懒惰列表:

fibs = undefined 

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

fibs = 0 : 1 : undefined 

其余的呢?这是fibs添加了fibs的移位版本。看这个。 zipWith f结合列表与使用功能f另一个列表:

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

而且我们在这里。就这样。

+15

您的解决方案可以说是规范的(+1),但我们应该努力帮助OP了解编译器消息。 – Ingo 2011-04-03 12:39:14

8

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

这会导致类型检查器尝试将类型“a”与类型“[a]”统一起来,这会发生检查错误。

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

3

让我们首先注意到,斐波那契数开始具有类型Int -> [Int] -> Int,而foldr相似的类型为(a -> b -> b) -> b -> [a] -> b,所以我们不能给到斐波纳契因为FOLDR我们不能Int -> [Int] -> Int统一a-> b-> b。这是错误信息的来源。

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

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

一些一般性的建议:如果你得到一个奇怪的类型错误,请确保您有所有顶级定义类型签名。这确保您的类型错误将在正确的定义中报告。这就是说,你的斐波那契定义很奇怪。

1

其他答案已经指出错误来自何处,并显示了在Haskell中非常紧凑和优雅的“标准”斐波那契数字定义。这里是另一种方式来定义它,这可能是更初学者友好:

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

的想法是保持不只有最后的轨道,但最后斐波那契数,可使用两人一组做的。使用这个技巧,定义递归关系非常容易。

我们从参数(0,1)开始,并使用next函数在此起始值上重新生成一个列表:[(0,1),(1,1),(1,2),(2,3),(3,5)...]。接下来唯一要做的就是“扔掉”对的第二个参数,由map fst $ ...完成。

[更新]

另外一个不错的定义(工作像zipWith-版本类似)是:

fibs = 0 : scanl (+) 1 fibs