Here is the algorithm in fairly idiomatic Clojure. I've tried to keep the names the same so that you can see how this code corresponds.
(def all? (partial every? identity))
(defn prime-gen []
(let [unfold
(iterate
(fn step [[primes n]]
(if (all?
(for [p primes :when (<= p (Math/sqrt n))]
(not= 0 (mod n p))))
[(conj primes n) (inc n)]
(recur [primes (inc n)])))
[[] 2])]
(map (comp peek first) (rest unfold))))
Every iteration of step
- appends the next prime to the first component of its argument and
- hands on the next candidate prime in the second component.
The last line picks out the appended primes from the iterations.
It works:
(take 11 (prime-gen))
=> (2 3 5 7 11 13 17 19 23 29 31)
We can also see some inefficiency:
The :when (<= p (Math/sqrt n)
clause (and its Python equivalent if p <= sqrt(n)
) are useless. We still go through all the discovered primes
instead of stopping when they get too big to be possible factors. To mend this,
- in Clojure, we replace the
:when
with a :while
;
- in Python, I think we wrap
primes
in a takewhile
instead of
following it with an if
(untested).
Even so, the algorithm is slow. For something faster, see lazy-primes3
from Christophe Grand's blog on the subject.