【发布时间】:2015-09-25 23:40:15
【问题描述】:
我写了以下筛子:
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
【问题讨论】:
-
我还没有弄清楚细节,但你很可能会因为你传递
sieve而陷入非终止计算(而不是只有sieve的适当前缀,即takeWhile (\p -> p^2 <= n) sieve)到isPrime。 -
@Jubobs 我尝试添加您建议的修改并且它有效!现在我真的很困惑。为什么它应该与
takeWhile (\p -> p^2 <= n)一起工作而不是takeWhile (<n)?