首先要注意的是,代码本身什么也不做。它只是一堆数学表达式,在我们尝试从中提取一些值之前,它的循环程度并不重要。我们如何做到这一点?
我们可以这样做:
print $ take 1 primes1
这里没有问题。我们可以在不查看任何递归代码的情况下获取 primes1 的第一个值,它明确地作为 2 存在。那么:
print $ take 3 primes1
让我们尝试扩展primes1
以获取一些值。为了使这些表达式易于管理,我现在忽略了print
andtake
部分,但请记住,我们只是因为它们才进行这项工作。primes1
是:
primes1 = 2 : filter prime [3..]
我们有我们的第一个值,我们第二个的第一步是扩展过滤器。如果这是一种严格的语言,我们会首先尝试扩展 [3..] 并陷入困境。过滤器的一个可能定义是:
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 和 find 中应用保护子句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,扩展该表达式,我们很快就会陷入循环。)