StackOverflowError в хвостовой рекурсивной функции - PullRequest
5 голосов
/ 22 ноября 2010

Следующий фрагмент кода Clojure приводит к java.lang.StackOverflowError, когда я вызываю его с помощью (avg-bids 4000 10 5).Я пытаюсь выяснить, почему, поскольку sum-bid записывается как хвостовая рекурсивная функция, так что это должно работать.Использование Clojure 1.2.

Кто-нибудь знает, почему это происходит?

(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))) 

1 Ответ

8 голосов
/ 22 ноября 2010

map ленив, и вы строите очень глубоко вложенное отображение отображений с помощью recur. Обратный след немного загадочный, но присмотритесь, и вы увидите карту, карту, карту ...

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)

Один из способов исправить это - поставить вокруг него doall, чтобы победить лень.

(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)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...