I referred to this post来计算函数nthPrimes
n的列表并返回第n个素数的列表:
import qualified Data.Set as PQ
main :: IO ()
main = print $ nthPrimes ns
where
ns = [1,3,10]
nthPrimes :: [Int] -> [Integer]
nthPrimes = map (primes !!)
primes :: [Integer]
primes = 2:sieve [3,5..]
where
sieve (x:xs) = x : sieve' xs (insertprime x xs PQ.empty)
sieve' (x:xs) table
| nextComposite == x = sieve' xs (adjust x table)
| otherwise = x : sieve' xs (insertprime x xs table)
where
(nextComposite,_) = PQ.findMin table
adjust x table
| n == x = adjust x (PQ.insert (n', ns) newPQ)
| otherwise = table
where
Just ((n, n':ns), newPQ) = PQ.minView table
insertprime p xs = PQ.insert (p*p, map (*p) xs)
因此,这将打印[3,7,31]
。
但是,由于primes
函数是惰性的,因此它将在每次调用中一次又一次地求值以获得n素数,但是实际上,如果我们知道{{ 1}}有一个最大限制(例如n
),因为1000
永不更改,并且计算primes
占用大量CPU和内存。
所以问题是如何对前X个元素强制执行primes
的求值,以便所有预先求值的元素都可以在从中获取的函数中重用?
我相信重用预先评估的元素会减少整体内存使用量,尤其是当primes
是一个很长的列表时,对吗?
答案 0 :(得分:5)
正如@chepner在注释中指出的那样,primes
是一个列表,而不是一个函数。 Haskell的工作方式是根据需要计算primes
列表中的元素,但是一旦计算,它们就会保存在内存中,并且不会一遍又一遍地重新计算。
您可以通过将模块加载到GHCi中来自己查看:
> :l MyPrimes
> :set +s
> nthPrimes [100000]
[1299721]
(6.45 secs, 3,246,628,344 bytes)
> nthPrimes [100001]
[1299743]
(0.01 secs, 188,184 bytes)
>
计算第100,000个素数大约需要6秒钟。一旦完成,计算第100,001个素数仅需0.01秒。