2

所以我决定玩弄 Haskell。我正在尝试解决 Project Euler 的第一个问题。以下是我的代码:

     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 甚至不包含递归步骤。

这是怎么回事?为什么它会如此壮观地破裂?我错过了什么模式?(我有单元素列表、多元素列表和空列表吗?)

编辑:对于任何关心我最初在上面提供的解决方案(在 John 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
4

1 回答 1

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将匹配一个单元素列表,因此您需要先检查该特殊情况。

于 2013-02-08T07:00:48.457 回答