2010-11-22 12 views
5

La siguiente parte del código Clojure da como resultado java.lang.StackOverflowError cuando lo llamo (avg-bids 4000 10 5). Intento averiguar por qué, dado que las ofertas de suma se escriben como una función recursiva de cola, eso debería funcionar. Usando Clojure 1.2.StackOverflowError en la función recursiva de cola

¿Alguien sabe por qué sucede esto?

(ns fixedprice.core 
    (:use (incanter core stats charts))) 

(def *bid-mean* 100) 

(defn bid [x std-dev] 
    (sample-normal x :mean *bid-mean* :sd std-dev)) 

(defn sum-bids [n offers std-dev] 
    (loop [n n sum (repeat offers 0)] 
    (if (zero? n) 
     sum 
     (recur (dec n) (map + sum (reductions min (bid offers std-dev))))))) 

(defn avg-bids [n offers std-dev] 
    (map #(/ % n) (sum-bids n offers std-dev))) 
+0

Una función recursiva de cola se llama a sí misma como lo último que hace. No veo nada de eso en tu código. – Gabe

+0

@Gabe: loop-recur provoca un comportamiento parecido a la recursividad de cola. Ver http://clojure.org/special_forms. – Ralph

+0

Ralph: 'loop-recur' es un patrón de bucle' for'. Llamar 'recurinc' como la última cosa en su función sería recursividad de cola, que no es lo que él hace. – Gabe

Respuesta

8

map es perezosa, y está la construcción de un mapeo muy profundamente anidado de asignaciones a través de recur. La traza es un poco críptico, pero mira de cerca y se puede ver un mapa, mapa, mapa ...

Caused by: java.lang.StackOverflowError 
     at clojure.lang.LazySeq.seq(LazySeq.java:56) 
     at clojure.lang.RT.seq(RT.java:450) 
     at clojure.core$seq.invoke(core.clj:122) 
     at clojure.core$map$fn__3699.invoke(core.clj:2099) 
     at clojure.lang.LazySeq.sval(LazySeq.java:42) 
     at clojure.lang.LazySeq.seq(LazySeq.java:56) 
     at clojure.lang.RT.seq(RT.java:450) 
     at clojure.core$seq.invoke(core.clj:122) 
     at clojure.core$map$fn__3699.invoke(core.clj:2099) 
     at clojure.lang.LazySeq.sval(LazySeq.java:42) 
     at clojure.lang.LazySeq.seq(LazySeq.java:56) 
     at clojure.lang.RT.seq(RT.java:450) 
     at clojure.core$seq.invoke(core.clj:122) 
     at clojure.core$map$fn__3699.invoke(core.clj:2099) 
     at clojure.lang.LazySeq.sval(LazySeq.java:42) 
     at clojure.lang.LazySeq.seq(LazySeq.java:56) 
     at clojure.lang.RT.seq(RT.java:450) 
     at clojure.core$seq.invoke(core.clj:122) 
     at clojure.core$map$fn__3699.invoke(core.clj:2099) 

Una forma de solucionarlo es poner doall alrededor de él para derrotar a la pereza.

(defn sum-bids [n offers std-dev] 
    (loop [n n sum (repeat offers 0)] 
    (if (zero? n) 
     sum 
     (recur (dec n) (doall (map + sum (reductions min (bid offers std-dev)))))))) 

user> (avg-bids 4000 10 5) 
(100.07129114746716 97.15856005697917 95.81372899072466 94.89235550905231 94.22478826109985 93.72441188690516 93.32420819224373 92.97449591314158 92.67155818823753 92.37275046342015) 
+1

Gracias Brian, que hizo el truco. Creo que tengo que ser un poco más atento a las consecuencias de las secuencias perezosas. –

Cuestiones relacionadas