I wrote the following sieve:
isPrime :: Integer -> [Integer] -> Bool
isPrime n = all (\i -> n `mod` i /= 0)
sieve :: [Integer]
sieve = 2 : [i | i <- [3,5..], isPrime i sieve]
but I don't understand why it gets stuck after the first value. Running take 10 sieve
results in [2,
and nothing happens. It probably has something to do with infinite recursion. May the problem be that sieve
is growing and at the same time it's used inside isPrime
? For that reason I also tried modifying isPrime
as follows, but without success:
isPrime :: Integer -> [Integer] -> Bool
isPrime n = all (\i -> n `mod` i /= 0) . takeWhile (<n)
EDIT: Surprisingly, @Jubobs's modification works:
isPrime :: Integer -> [Integer] -> Bool
isPrime n = all (\i -> n `mod` i /= 0) . takeWhile (\p -> p^2 <= n)
I cannot understand why this version of takeWhile
works while the other does not. I see that with my previous version I tested many unnecessary divisors, but they were in a finite number nontheless.
The code should basically be equivalent to the following Python code:
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
You cause an infinite recursion by applying all
to the entire sieve
and not just the values which you sieved so far. I.e. For the second element, isPrime
tests all values in sieve
instead of just 2
.
In your Python version, you wrote
is_prime(n, ps)
which only tests n
against all numbers sieved so far. The Python equivalent of what you did in Haskell is basically
is_prime(n, sieve())
Now, using takeWhile (<n)
won't help because that also requires calculating the sieve elements. Imagine what happens for the second element of sieve
(which should be 3): it tests all values of the sieve for which < 3
holds, but in order to test that you actually need to evaluate the sieve elements. So you still have an infinite recursion.