为什么这个Haskell代码片段不是无限递归的?

时间:2011-12-12 03:12:16

标签: haskell primes factorization

为了帮助我学习Haskell,我正在解决Project Euler上的问题。在解决了每个问题之后,我会针对Haskell wiki检查我的解决方案,以尝试学习更好的编码实践。以下是the solutionproblem 3

primes = 2 : filter ((==1) . length . primeFactors) [3,5..]

primeFactors n = factor n primes
  where
    factor n (p:ps) 
        | p*p > n        = [n]
        | n `mod` p == 0 = p : factor (n `div` p) (p:ps)
        | otherwise      = factor n ps

problem_3 = last (primeFactors 317584931803)

我天真的解读是,primes是根据primeFactors来定义的,primes是根据primeFactors 9定义的。因此评估factor 9 primes将遵循此过程:

  1. 评估primes
  2. 询问primes第一个元素,即2。
  3. 询问primeFactors 3下一个元素。
  4. 作为此过程的一部分,请评估primes
  5. 询问primes第一个元素,即2。
  6. 询问primeFactors 3下一个元素。
  7. 作为此过程的一部分,请评估{{1}}。
  8. ...
  9. 换句话说,步骤2-4将无限重复。显然我错了,因为算法终止了。我在这里犯了什么错误?

3 个答案:

答案 0 :(得分:17)

primeFactors只能读取它正在评估的数字的平方根。它永远不会在列表中进一步查看,这意味着它永远不会“赶上”它正在测试包含在列表中的数字。因为Haskell是惰性的,这意味着primeFactors测试会终止。

要记住的另一件事是primes不是每次访问时都评估为列表的函数,而是一个懒惰构造的列表。因此,一旦访问了第15个元素,第二次访问它是“免费的”(例如,它不需要任何进一步的计算)。

答案 1 :(得分:8)

凯文的答案令人满意,但请允许我指出你逻辑中的缺陷。这是#6错了。所以我们正在评估primeFactors 3

primeFactors 3          ==>
factor 3 primes         ==>
factor 3 (2 : THUNK)    ==>
2*2 > 3 == True         ==>
[3]

永远不需要评估THUNK以确定primeFactor 3[3]

答案 2 :(得分:7)

primeFactors 3不会询问primes下一个元素,只会询问第一个元素,因为2*2已大于3

相关问题