2013-02-08 72 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

相關問題