我写了以下筛子:
isPrime :: Integer -> [Integer] -> Bool
isPrime n = all (\i -> n `mod` i /= 0)
sieve :: [Integer]
sieve = 2 : [i | i <- [3,5..], isPrime i sieve]
但我不明白为什么它在第一个值之后会卡住。运行take 10 sieve
结果[2,
并没有任何反应。它可能与无限递归有关。问题可能在于它sieve
正在增长并且同时在内部使用isPrime
?出于这个原因,我也尝试修改isPrime
如下,但没有成功:
isPrime :: Integer -> [Integer] -> Bool
isPrime n = all (\i -> n `mod` i /= 0) . takeWhile (<n)
编辑:令人惊讶的是,@Jubobs 的修改有效:
isPrime :: Integer -> [Integer] -> Bool
isPrime n = all (\i -> n `mod` i /= 0) . takeWhile (\p -> p^2 <= n)
我不明白为什么这个版本的takeWhile
作品,而另一个没有。我看到在我以前的版本中,我测试了许多不必要的除数,但它们的数量仍然有限。
该代码应该基本上等同于以下 Python 代码:
def is_prime(n, ps):
for i in ps:
if n % i == 0: return False
return True
def sieve():
yield 2
n = 3
ps = [2]
while True:
if is_prime(n, ps):
yield n
ps.append(n)
n += 2