Clojure StackOverflowError on-tail递归函数

Clojure StackOverflowError on-tail递归函数,clojure,Clojure,下面的Clojure代码在我用(avg bids 4000 10 5)调用它时会生成java.lang.StackOverflowerr。我试图找出原因,因为sum bids是作为一个尾部递归函数编写的,所以应该可以工作。使用Clojure 1.2 有人知道为什么会这样吗 (ns fixedprice.core (:use (incanter core stats charts))) (def *bid-mean* 100) (defn bid [x std-dev] (sample

下面的Clojure代码在我用(avg bids 4000 10 5)调用它时会生成java.lang.StackOverflowerr。我试图找出原因,因为sum bids是作为一个尾部递归函数编写的,所以应该可以工作。使用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))) 

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)

尾部递归函数作为最后一件事调用自己。我在您的代码中没有看到类似的内容。@Gabe:loop recur会导致类似尾部递归的行为。参见.Ralph:
循环重现
是循环模式的
。调用
recur
函数中的最后一件事是尾部递归,这不是他所做的。
recur
会在它不处于尾部位置时抱怨。谢谢Brian,这就成功了。我想我必须稍微小心一点,更加意识到懒惰序列的后果。