Ich habe diese Umsetzung des Siebes von Eratosthenes in Clojure:Clojure - tail rekursiven Sieb von Eratosthenes
(defn sieve [n]
(loop [last-tried 2 sift (range 2 (inc n))]
(if
(or (nil? last-tried) (> last-tried n))
sift
(let [filtered (filter #(or (= % last-tried) (< 0 (rem % last-tried))) sift)]
(let [next-to-try (first (filter #(> % last-tried) filtered))]
(recur next-to-try filtered))))))
Für größere n
(wie 20000) endet mit Stapelüberlauf. Warum funktioniert die Tail Call Elimination hier nicht? Wie man es repariert?
Als eine Randnotiz, aber das ist nicht das Sieb von Eratosthenes. SoE führt keine Restoperationen durch, nur Addition und "Durchstreichen". Siehe http://www.cs.hmc.edu/~oneill/papers/Sieve-JFP.pdf für eine ausführliche Diskussion (es ist eine tolle Lektüre!); Für eine schöne "inkrementelle" SoE-Implementierung in Clojure von Christophe Grand, siehe http://clj-me.cgrand.net/2009/07/30/everybody-loves-the-sieve-of-eratosthenes/ (es ist auch die schnellste Version, die ich bisher gesehen habe). –
@ Michał Marczyk danke. Ich würde sagen, dass "crossing out" äquivalent zu "filtering" ist, und "addition" in diesem Algorithmus ist gleichbedeutend mit "multiplication" und folglich "rest". –
Nicht wirklich. Das Ergebnis ist natürlich dasselbe, aber die algorithmische Komplexität ist sehr unterschiedlich. –