In a future course, I'll be having a discipline that uses Python with an emphasis of using sequences and generators and that kind of stuff inn Python.
I've been following an exercise list to exercise these parts. I'm stuck on an exercise that asks for a prime generator. Up until now, I haven't used Python very much, but I've read and done most of the exercises in SICP. There, they present the following program that makes use of the sieve of Eratosthenes to generate a lazy list of primes.
(define (sieve stream)
(cons-stream
(stream-car stream)
(sieve (stream-filter
(lambda (x)
(not (divisible? x (stream-car stream))))
(stream-cdr stream)))))
(define primes (sieve (integers-starting-from 2)))
In Python, from what I have read, the closest thing is generators So I tried translating it to the following.
import itertools
def sieve(seq):
n = next(seq)
yield n
sieve(filter(lambda x: x % n != 0, seq))
def primes():
return sieve(itertools.count(2))
print(list(itertools.islice(primes(),10)))
But it prints only [2]
.
I figure that this is because the result of the recursive call to sieve is just discarded, instead of running the function again, as I first expected.
To try to remedy this, I tried using a loop instead:
def sieve(seq):
def divisible(n):
return lambda x: x % n != 0
while True:
n = next(seq)
yield n
seq = sieve(filter(divisible(n), seq))
This works insofar as that I can generate the first 9 primes, but if I ask for the tenth a RecursionError
is raised.
So, my question is how can I improve this to be able to calculate larger primes?
PS: There is already a proposed implementation of a sieve generator in https://stackoverflow.com/a/568618/6571467, but it explicitly deals with the previous primes in the sieve. Whereas in the lazy list paradigm, the objective is to abstract from the order the operations are actually executed.