2013-02-08 73 views
2

我正在尝试使用Haskell解决Project Euler上的第二个问题。这个问题相当简单 - 将平均斐波纳契数字加起来小于4000000.(我是强迫症,我在暗示一个稍微修改过的函数 - 一个允许任意限制的函数)。Haskell无法构造无限类型:a0 = [a0]

我最初的代码为:

euler2 limit (num1:num2) 
    |(num1>limit) = 0 
    |((num2>limit) && ((mod num1 2) == 0)) = num1 
    |(num2>limit) = 0 
    |(((mod num1 2) == 0) && ((mod num2 2) == 0)) = num1+num2+(euler2 limit [num1+num2,num1+num2+num2]) 
    |((mod num1 2) == 0) = num1+(euler2 limit [num1+num2,num1+num2+num2]) 
    |((mod num2 2) == 0) = num2+(euler2 limit [num1+num2,num1+num2+num2]) 
    |otherwise = euler2 limit [num1+num2,num1+num2+num2] 
euler2 limit [] = euler2 limit [1,2] 

这将产生以下错误:

Occurs check: cannot construct the infinite type: a0 = [a0] 
In the second argument of `(>)', namely `limit' 
In the first argument of `(&&)', namely `(num2 > limit)' 
In the expression: ((num2 > limit) && ((mod num1 2) == 0)) 

现在通过一些试验和错误,我已经意识到,它正试图强制转换num2作为一个列表,和这个小小的变化:

euler2 limit (num1:num2:[]) | (num1 > limit) = 0 

修复了这个问题。我的问题是为什么?发生了什么,为什么它拒绝将num1num2作为Ints?

+0

尝试添加一个明确的类型签名到你的euler2函数中:'euler2 :: Integer [Integer]'(或类似的东西......)。修复类型可能会导致更简单的错误消息。 – hugomg 2013-02-08 19:54:05

+0

'num1'是一个'Int',你的问题是'num2'不是;它是'Ints'的列表。 – sabauma 2013-02-08 19:56:26

+0

对,但明确指出:[]感觉像脏兮兮的黑客。有什么办法可以更优雅地执行这种事情吗?什么是“Haskell方式”? – 2013-02-08 19:58:58

回答

6

类型的(:)

(:) :: a -> [a] -> [a] 

如果你有一个模式匹配

euler2 limit (num1:num2) 

名称num1num2必将构造(:)的相应参数(如果提供的参数一个非空列表),因此num2是一个列表,其元素的类型为num1

如果匹配

(num1:num2:[]) 

中隐含括号

(num1 : (num2 : [])) 

现在num2 : []与那就是顶级(:)的第二个参数列表匹配,并且匹配成功,如果提供的参数是一个包含两个元素的列表,则将num2绑定到第二个列表元素。

+0

只会添加(:)运算符/列表构造函数的隐式右关联性是由于其正确的固定性 – 2013-02-10 05:18:39

相关问题