所以我正在研究一种懒惰地生成素数的方法,我想出了这三个定义,它们都以等效的方式工作 - 只是检查每个新整数是否在所有前面的素数中都有一个因子:
primes1 :: [Integer]
primes1 = mkPrimes id [2..]
where mkPrimes f (x:xs) =
if f (const True) x
then
let g h y = y `mod` x > 0 && h y in
x : mkPrimes (f . g) xs
else
mkPrimes f xs
primes2 :: [Integer]
primes2 = mkPrimes id (const True) [2..]
where mkPrimes f f_ (x:xs) =
if f_ x
then
let g h y = y `mod` x > 0 && h y in
x : mkPrimes (f . g) ( f $ g $ const True) xs
else
mkPrimes f f_ xs
primes3 :: [Integer]
primes3 = mkPrimes [] [2..]
where mkPrimes ps (x:xs) =
if all (\p -> x `mod` p > 0) ps
then
x : mkPrimes (ps ++ [x]) xs
else
mkPrimes ps xs
所以在我看来primes2
应该比 快一点primes1
,因为它避免了
f_ = f (const True)
对每个整数重新计算(我认为这需要按照我们迄今为止找到的素数数量的顺序工作),并且只在遇到新的时更新它主要。
仅从不科学的测试(take 1000
在 ghci 中运行)看来,它的运行速度似乎primes3
比primes2
.
我是否应该从中吸取教训,并假设如果我可以将函数表示为数组上的操作,我应该以后一种方式实现它以提高效率,还是这里发生了其他事情?