我写了下面的筛子:
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
答案 0 :(得分:4)
通过将all
应用于整个sieve
而不仅仅是您到目前为止所筛选的值,您可以进行无限递归。即对于第二个元素,isPrime
会在sieve
中测试所有值,而不仅仅是2
。
在你的Python版本中,你写了
is_prime(n, ps)
仅对所有到目前为止被筛选的数字进行n
测试。你在Haskell中所做的Python相当于
is_prime(n, sieve())
现在,使用takeWhile (<n)
无济于事,因为这也需要计算筛子元素。想象一下sieve
的第二个元素(应该是3)会发生什么:它测试< 3
所持有的筛子的所有值,但是为了测试你实际上需要评估筛子元素。所以你仍然有一个无限的递归。
答案 1 :(得分:0)
我会说筛子中的理解列表在完成之前不会结束,永远不会。要像这样使用,筛子必须逐个返回元素。例如,[1..]
将1, 2 ,3 ,4...
显示为无穷大,但您的筛只显示[2
。
或者显然不是我所说的