В настоящее время я внедряю решение для одной из задач Project Euler, а именно - Sieve of Eratosthenes (https://en.wikipedia.org/wiki/Sieve_of_Eratosthenes), в Clojure. Вот мой код:
(defn cross-first-element [coll]
(filter #(not (zero? (rem % (first coll)))) coll))
(println
(last
(map first
(take-while
(fn [[primes sieve]] (not (empty? sieve)))
(iterate
(fn [[primes sieve]] [(conj primes (first sieve)) (cross-first-element sieve)])
[[] (range 2 2000001)])))))
Основная идея состоит в том, чтобы иметь две коллекции - простые числа, уже извлеченные из сита, и оставшееся само сито. Мы начинаем с пустого primes
, и пока сито не станет пустым, мы выбираем его первый элемент и добавляем его к primes
, а затем вычеркиваем кратные его числа из сита. Когда он исчерпан, мы знаем, что у нас есть все простые числа из двух миллионов в простых числах.
К сожалению, как бы хорошо оно ни работало для маленькой верхней границы сита (скажем, 1000), оно вызывает java.lang.StackOverflowError
с длинной трассировкой стека с повторяющейся последовательностью:
...
clojure.lang.RT.seq (RT.java:531)
clojure.core$seq__5387.invokeStatic (core.clj:137)
clojure.core$filter$fn__5878.invoke (core.clj:2809)
clojure.lang.LazySeq.sval (LazySeq.java:42)
clojure.lang.LazySeq.seq (LazySeq.java:51)
...
Где концептуальная ошибка в моем решении? Как это исправить?