繁体   English   中英

懒惰的质数列表

[英]Lazy List of Prime Numbers

如何在 Haskell 中实现素数列表,以便可以懒惰地检索它们?

我是 Haskell 的新手,想了解惰性求值功能的实际用途。

这是一个简短的 Haskell 函数,它从文学程序中枚举素数

primes :: [Integer]
primes = sieve [2..]
  where
    sieve (p:xs) = p : sieve [x|x <- xs, x `mod` p > 0]

显然,这不是Eratosthenes 的筛子(谢谢,Landei)。 我认为这仍然是一个很有启发性的例子,它表明你可以用 Haskell 编写非常优雅的短代码,并且表明选择错误的数据结构会如何严重影响效率。

我建议采用本文中的一种实现: http : //www.cs.hmc.edu/~oneill/papers/Sieve-JFP.pdf

在haskell wiki 中有许多用于懒惰生成素数序列的解决方案。 第一个也是最简单的是延迟特纳筛:(旧版本......注意)

primes :: [Integer]
primes = 2: 3: sieve (tail primes) [5,7..]
 where 
  sieve (p:ps) xs = h ++ sieve ps [x | x <- t, x `rem` p /= 0]  
                                -- or:  filter ((/=0).(`rem`p)) t
                  where (h,~(_:t)) = span (< p*p) xs

来自@nikie 的公认答案不是很有效,在几千之后变得相对缓慢,但@sleepynate 的答案要好得多。 我花了一些时间来理解它,因此这里是相同的代码,但只是更清楚地命名了变量:

lazyPrimes :: [Integer]
lazyPrimes = 2: 3: calcNextPrimes (tail lazyPrimes) [5, 7 .. ]
  where
    calcNextPrimes (p:ps) candidates =
      let (smallerSquareP, (_:biggerSquareP)) = span (< p * p) candidates in
      smallerSquareP ++ calcNextPrimes ps [c | c <- biggerSquareP, rem c p /= 0]

主要思想是,下一个素数的候选者已经不包含可以被任何小于给定函数的第一个素数的素数整除的数字。 所以如果你打电话

calcNextPrimes (5:ps) [11,13,17..]

候选列表不包含数字,即可以被23整除,这意味着第一个非质数候选将是5 * 5 ,因为5* 25 * 35 * 4已经被消除。 这使您可以将所有小于 5 的平方的候选者直接添加到素数中,然后筛选其余的以消除所有可被 5 整除的数。

primes = 2 : [x | x <- [3..], all (\y -> x `mod` y /= 0) 
                   (takeWhile (<= (floor . sqrt $ fromIntegral x)) primes)]

列表中最初为2 ,对于每个大于2 的整数x ,检查primes所有y是否满足y <= sqrt(x) , x mod y != 0 ,这意味着x除了1和本身。

暂无
暂无

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

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