2013-02-08 53 views
2

所以我決定玩弄Haskell。我試圖解決項目歐拉的第一個問題。以下是我的代碼:Haskell生成非詳盡模式錯誤

 euler1 limit (div:divisors) = if limit > 1 then (euler1 limit divisors) + (euler1 limit (div:[])) + (euler1 (limit-1) (div:divisors)) else 0 
    euler1 limit (divisor:[]) = if limit > 1 && (mod limit divisor) == 0 then limit else 0 
    euler1 limit [] = 0 

然而,當我通過ghci中運行它,會發生以下情況:

 euler1 9 [3,5] 
    *** Exception: <interactive>:3:5-90: Non-exhaustive patterns in function euler1 

進一步調試:

 euler1 5 [] 
    0 

    euler1 5 [5] 
    *** Exception: <interactive>:3:5-90: Non-exhaustive patterns in function euler1 

這表明,斷碼是在第二種情況下(帶有一個元素的列表),其中euler1甚至不包含遞歸步驟。

怎麼回事?爲什麼它會如此壯觀地破碎?我錯過了什麼樣的模式? (我有一個元素列表,多元素的列表,而空單沒有?)

編輯:任何人誰在乎我最初上面提供的解決方案(與約翰LS輝煌的幫助)仍然是不完全正確,因爲它會計算多於一個除數多於一次的項目。最後的正確的工作算法如下:

 euler1 limit (divisor:[]) = if ((limit > 1) && ((mod limit divisor) == 0)) then limit else 0 
     euler1 limit (div:divisors) | ((limit > 1) && (euler1 limit (div:[]))==0) = (euler1 limit divisors) + (euler1 (limit-1) (div:divisors)) | ((limit > 1) && (euler1 limit (div:[]))/=0) = (euler1 limit (div:[])) + (euler1 (limit-1) (div:divisors)) |limit > 1 = euler1 (limit-1) (div:divisors) | otherwise = 0 
     euler1 limit [] = 0 

回答

10

你在ghci中定義了這個嗎?如果你這樣做:

Prelude> let euler1 limit (divisor:[]) = if limit > 1 && (mod limit divisor) == 0 then limit else 0 
Prelude> let euler1 limit [] = 0 

第二個定義會影響第一個,導致非窮舉模式失敗。

相反,你應該使用ghci中的多行語法

Prelude> :{ 
Prelude| let euler1 limit (divisor:[]) = if limit > 1 && (mod limit divisor) == 0 then limit else 0 
Prelude|  euler1 limit (div:divisors) = if limit > 1 then (euler1 limit divisors) + (euler1 limit (div:[])) + (euler1 (limit-1) (div:divisors)) else 0 
Prelude|  euler1 limit [] = 0 
Prelude| :} 

另外請注意,我換了前兩名語句的順序。 div:divisors將匹配單個元素列表,因此您需要首先檢查特殊情況。

+0

謝謝!我從來沒有找到這個! (我相當肯定我有條件/ mod調用時出現了某種語法錯誤)xD –

+5

@AbrahamP真的很值得在一個文件中保存你的函數,Euler.hs,並且執行:l在ghci中加載Euler.hs來加載它,比直接在ghci中編寫要容易得多。 – AndrewC

+1

@AndrewC我同意,這就是我幾乎總是工作的方式。但是多線符號在其他情況下非常方便,並且它不是廣爲人知的,所以我藉此機會宣傳它。 –