为什么这个Haskell代码片段不是无限递归的? [英] Why is this Haskell code snippet not infinitely recursive?
问题描述
primes = 2:filter((== 1 )。length。primeFactors)[3,5 ..]
primeFactors n =因子n素数
其中
因子n(p:ps)
| p * p> n = [n]
| n'mod` p == 0 = p:factor(n`div` p)(p:ps)
|否则=系数n ps
problem_3 = last(primeFactors 317584931803)
我的天真地阅读这篇文章的是 primes
是根据 primeFactors
来定义的,它由素数
。因此,评估 primeFactors 9
会遵循以下过程:
$ b
- 评估
factor 9 primes
。 - 询问
素数
为其第一个元素,即2。 >
- 为其下一个元素询问
primes
。
- 作为此过程的一部分,评估
primeFactors 3
。 - 询问
素数
为其第一个元素,即2。 >
- 为其下一个元素询问
primes
。
- 作为此过程的一部分,评估
primeFactors 3
。 - ...
- Evaluate
factor 9 primes
. - Ask
primes
for its first element, which is 2. - Ask
primes
for its next element. - As part of this process, evaluate
primeFactors 3
. - Ask
primes
for its first element, which is 2. - Ask
primes
for its next element. - As part of this process, evaluate
primeFactors 3
. - ...
换句话说,步骤2-4将无限重复。很明显,我错了,算法终止。我在这里犯了什么错误?
primeFactors
到它正在评估的数字的平方根。它从来没有在列表中看得更远,这意味着它永远不会追上它正在测试列入列表中的数字。因为Haskell是懒惰的,这意味着 primeFactors
测试不会终止。
primes
不是每次访问时都会计算列表的函数,而是一个懒惰构造的列表。因此,一旦第15个元素被访问过一次,第二次访问它就是免费(例如,它不需要任何进一步的计算)。 To help me learn Haskell, I am working through the problems on Project Euler. After solving each problem, I check my solution against the Haskell wiki in an attempt to learn better coding practices. Here is the solution to problem 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)
My naive reading of this is that primes
is defined in terms of primeFactors
, which is defined in terms of primes
. So evaluating primeFactors 9
would follow this process:
In other words, steps 2-4 would repeat infinitely. Clearly I am mistaken, as the algorithm terminates. What mistake am I making here?
primeFactors
only ever reads up to the square root of the number it's evaluating. It never looks further in the list, which means it never "catches up" to the number it's testing for inclusion in the list. Because Haskell is lazy, this means that the primeFactors
test does terminate.
The other thing to remember is that primes
isn't a function that evaluates to a list each time you access it, but rather a list that's constructed lazily. So once the 15th element has been accessed once, accessing it a second time is "free" (e.g. it doesn't require any further calculation).
这篇关于为什么这个Haskell代码片段不是无限递归的?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!