utilizar recursión recursivos recursividad recursiva que puede programacion pilas funcion ejemplos cuándo casos aplica recursion clojure primes lazy-evaluation lazy-sequences

recursion - recursión - recursividad javascript ejemplos



Función recursiva que causa un desbordamiento de la pila (2)

Algorítmicamente, el problema es que continúas filtrando cuando ya no hay más propósito. Al detenerse tan pronto como sea posible se logra una reducción cuadrática en la profundidad de recursión ( sqrt(n) vs. n ):

(defn sieve [potentials primes] (if-let [p (first potentials)] (if (> (* p p) (last potentials)) (concat primes potentials) (recur (filter (fn [n] (not= (mod n p) 0)) potentials) (conj primes p))) primes))

Funciona bien para 16,000 (realizando solo 30 iteraciones en lugar de 1862), y para 160,000 también, en ideone . Incluso funciona un 5% más rápido sin el doall .

Estoy tratando de escribir una función de criba simple para calcular números primos en clojure. He visto this pregunta sobre cómo escribir una función de tamiz eficiente, pero todavía no llegué a ese punto. En este momento solo intento escribir un tamiz muy simple (y lento). Esto es lo que se me ocurrió:

(defn sieve [potentials primes] (if-let [p (first potentials)] (recur (filter #(not= (mod % p) 0) potentials) (conj primes p)) primes))

Para rangos pequeños funciona bien, pero causa un desbordamiento de pila para rangos grandes:

user=> (sieve (range 2 30) []) [2 3 5 7 11 13 17 19 23 29] user=> (sieve (range 2 15000) []) java.lang.StackOverflowError (NO_SOURCE_FILE:0)

Pensé que al recur esto sería una construcción de bucle que no consume pila ¿Qué me estoy perdiendo?


Estás siendo golpeado por la pereza del filter . Cambiar (filter ...) a (doall (filter ...)) en su formulario recur y el problema debería desaparecer.

Una explicación más profunda:

La llamada al filter devuelve un seq perezoso, que materializa los elementos reales del seq filtrado según sea necesario. Como está escrito, las pilas de códigos filter filter tras filter ..., agregando un nivel más de filter en cada iteración; en algún momento esto explota. La solución es forzar el resultado completo en cada iteración para que el siguiente haga su filtrado en un seq completamente realizado y devuelva un seq completamente realizado en lugar de agregar una capa extra de procesamiento de seq perezoso; eso es lo que hacen todos.