2010-11-22 12 views
5

次のClojureコードは、(avg-bids 4000 10 5)で呼び出すとjava.lang.StackOverflowErrorになります。なぜ私は総和がテール再帰関数として書かれているのか理解しようとするので、うまくいくはずです。 Clojure 1.2の使用。tail-recursive関数のStackOverflowError

これはなぜ起こるのですか?

(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

末尾再帰関数は、最後のものとして自身を呼び出します。私はあなたのコードのようなものは表示されません。 – Gabe

+0

@Gabe:loop-recurは、テール再帰的な振る舞いを引き起こします。 http://clojure.org/special_formsを参照してください。 – Ralph

+0

Ralph: 'loop-recur'は' for'ループパターンです。あなたの関数の中で最後のものとして 'recur'を呼び出すことは、彼がやっていることではないテール再帰です。 – Gabe

答えて

8

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) 
+1

ブライアン、ありがとう、トリックでした。私はちょっと怠惰なシーケンスの結果をもっと気にしなければならないと思う。 –

関連する問題