首先需要注意的是,单独看这段代码是没有任何作用的。它只是一些数学表达式的组合,除非我们尝试从中提取一些值,否则它的循环方式并不重要。那么我们该如何提取这些值呢?
我们可以采用以下方式:
print $ take 1 primes1
这里没有问题。我们可以直接获取primes1的第一个值,而不需要查看任何递归代码,因为它明确地表示为2。那么接下来呢:
print $ take 3 primes1
让我们尝试扩展primes1
以获取一些值。为了使这些表达式易于管理,我现在忽略了print
和take
部分,但要记住,我们只是因为它们才做这项工作。 primes1
是:
primes1 = 2 : filter prime [3..]
我们有了第一个值,而第二个值的第一步是扩展过滤器。
如果这是一种严格的语言,我们将首先尝试扩展 [3..] 并陷入困境。filter 的一个可能定义如下:
filter f (x:xs) = if f x then x : filter f xs else filter f xs
这将会产生:
primes1 = 2 : if prime 3 then 3 : filter prime [4..] else filter prime [4..]
我们接下来的步骤是确定
prime 3
是真还是假,因此让我们使用
prime
、
ldp
和
ldpf
的定义来扩展它。
primes1 = 2 : if ldp 3 == 3 then 3 : filter prime [4..] else filter prime [4..]
primes1 = 2 : if ldpf primes1 3 == 3 then 3 : filter prime [4..] else filter prime [4..]
现在,事情变得有趣了,primes1 引用了自己,而 ldpf 需要第一个值来进行计算。幸运的是,我们可以很容易地获取第一个值。
primes1 = 2 : if ldpf (2 : tail primes) 3 == 3 then 3 : filter prime [4..] else filter prime [4..]
现在,我们在ldpf中应用守卫条款,并发现
2^2 > 3
,因此
ldpf (2 : tail primes) 3 = 3
。
primes1 = 2 : if 3 == 3 then 3 : filter prime [4..] else filter prime [4..]
primes1 = 2 : 3 : filter prime [4..]
现在我们有了第二个值。请注意,我们的评估右侧从未特别增大,并且我们从未需要远距离遵循递归循环。
primes1 = 2 : 3 : if prime 4 then 4 : filter prime [5..] else filter prime [5..]
primes1 = 2 : 3 : if ldp 4 == 4 then 4 : filter prime [5..] else filter prime [5..]
primes1 = 2 : 3 : if ldpf primes1 4 == 4 then 4 : filter prime [5..] else filter prime [5..]
primes1 = 2 : 3 : if ldpf (2 : tail primes1) 4 == 4 then 4 : filter prime [5..] else filter prime [5..]
我们使用守卫子句rem 4 2 == 0
,因此我们在这里得到2。
primes1 = 2 : 3 : if 2 == 4 then 4 : filter prime [5..] else filter prime [5..]
primes1 = 2 : 3 : filter prime [5..]
primes1 = 2 : 3 : if prime 5 then 5 : filter prime [6..] else filter prime [6..]
primes1 = 2 : 3 : if ldp 5 == 5 then 5 : filter prime [6..] else filter prime [6..]
primes1 = 2 : 3 : if ldpf primes1 5 == 5 then 5 : filter prime [6..] else filter prime [6..]
primes1 = 2 : 3 : if ldpf (2 : tail primes) 5 == 5 then 5 : filter prime [6..] else filter prime [6..]
没有匹配的守卫,所以我们进行递归:
primes1 = 2 : 3 : if ldpf (tail primes) 5 == 5 then 5 : filter prime [6..] else filter prime [6..]
primes1 = 2 : 3 : if ldpf (3 : tail (tail primes)) 5 == 5 then 5 : filter prime [6..] else filter prime [6..]
现在
3^2 > 5
,所以该表达式的值为5。
primes1 = 2 : 3 : if 5 == 5 then 5 : filter prime [6..] else filter prime [6..]
primes1 = 2 : 3 : 5 : filter prime [6..]
我们只需要三个值,因此评估可以停止。
所以,现在回答你的问题。懒惰列表是仅需要我们评估所需内容的列表,并且2很有用,因为它确保当我们到达递归步骤时,我们已经计算出足够的值。(如果我们不知道2,想象一下扩展该表达式,我们很快就会陷入循环中。)