繁体   English   中英

Haskell如何评估该素数函数?

[英]How does Haskell evaluate this primes function?

我发现很难理解Haskell如何评估此primes函数。 primes函数是一遍又一遍地求值,还是primeFactors函数中的primes会指向第一个primes

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

main :: IO ()
main = print $ length . take 100000 $ primes

primes只是一个列表。 它的第一个元素为2,其余元素取自使用(部分)函数primeFactors过滤的奇整数列表。

primeFactors使用primes 这不是通函吗?

不完全的。 由于Haskell是惰性的,因此primeFactors不需要一次使用primes所有值,而只需要小于或等于其参数平方根的值( p:psprimes匹配,但仅当p*p <= n时才需要ps p*p <= n ),这些素数都是通过先前对primeFactors调用找到的。

例如,跟踪对primeFactors的前几个调用。 为简便起见,令b = (==1) . length . primeFactors b = (==1) . length . primeFactors b = (==1) . length . primeFactors

primeFactors 3 == factor 3 primes
               -- only unpack as much of primes as we need for the next step
               == factor 3 (2:filter b [3,5..])
               -- because 2*2 > 3, that's only one level
               == [3]

因此,由于b [3]为真,我们知道3是primes的下一个元素。 也就是说, primes = 2:3:filter b [5,7..]

primeFactors 5 == factor 5 primes
               == factor 5 (2:3:filter b [3,5..])
               -- 2*2 > 5 is false, as is 5 `mod` 2 == 0, so
               == factor 5 (3:filter b [3,5..])
               -- 3*3 > 5, so
               == [5]

b [5]是正确的,因此5primes的下一个元素。

primeFactors 7 == factor 7 primes
               == factor 7 (2:3:5:filter b [3,5..])
               == factor 7 (3:5:filter b [3,5..])
               -- 3*3 > 7
               == [7]

b [7]是正确的,因此7是质primes的下一个元素。 (似乎所有内容都添加到质primes ,不是吗?再调用primeFactors会显示情况并非如此)

primeFactors 9 == factor 9 primes
               == factor 9 (2:3:5:7:filter b [3,5..])
               -- 2*2 > 9 and 9 `mod` 2 == 0 are false
               == factor 9 (3:5:7:filter b [3,5..])
               -- 3*3 > 9 is false, but 9 `mod` 3 == 0 is true, so
               == 3 : factor (9 `div` 3) (3:5:7:filter b [3,5..])
               == 3 : factor 3 (3:5:7:filter b [3,5..])
               -- 3*3 > 3 is false, but 3 `mod` 3 == 0, so
               == 3 : [3] == [3,3]

但是由于b [3,3]为假,所以9 不是 primes的元素。 所以现在我们有了

 primes = 2:3:5:7:filter b [3,5..])

要追踪这个过程是一个漫长而乏味的过程,但是您应该感觉到primes始终位于primeFactors “前面”; primeFactors所需的primes元素始终由先前对primeFactors调用确定。

Haskell将如何评估该素数函数?

如问题出你的代码,它打印出第一个10万张素数,所以如何primes工作?

首先,生成第一个素数很简单,只需列表的第一个元素:

2 : filter ((==1) ...

那是2 ,对于下一个,我们需要应用primeFactors函数为

primeFactors 3 = factor 3 primes

现在可能会使Haskell的新手感到困惑,如何评估上述表达式中的primes 答案是,这只是一个元素为[2,...]的列表,这要归功于惰性求值,现在,我们不需要求值primes函数生成的所有primes 我们只需要评估下一个 ,然后看看会发生什么。 因此,我们得到2 ,上面的表达式变为:

 primeFactors 3 = factor 3 [2,..]

factor 3 (2:ps) | 2 * 2 > 3 = [3]

因此, primeFactors 3 [3]

所以

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

我们现在成功地生成了2个质数,但是我们需要100000,接下来呢? 显然,我们将5应用于以下表达式:

2: filter ((==1) . length . primeFactors) 5

重复上述步骤:

primeFactors 5 = factor 5 [2,3,..]

这次我们在列表中有2个元素:

factor 5 [2,3..]

factor 5 [2,3..] | otherwise = factor 5 [3,...]

factor 5 [3,...] | 3 * 3 > 5 = [5]

然后一次又一次重复直到生成100000个质数,再一次,由于懒惰的求值,我们不需要100001个质数,因此计算停止并打印出结果。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM