使用lazy-seq确定代码中StackOverflow的原因

时间:2013-06-01 01:50:13

标签: clojure

我有以下代码段:

(defn explode [e]
  (seq [e e e e]))

(defn f [coll]
  (when-first [e coll]
    (cons e 
          (lazy-seq (f (lazy-cat (next coll)
                                 (explode e)))))))

当我尝试访问元素时,出现StackOverflow错误:

user=> (nth (f (seq [1 2 3])) 1000)
3
user=> (nth (f (seq [1 2 3])) 10000)

StackOverflowError   clojure.core/concat/fn--3923 (core.clj:678)

如何以不会破坏堆栈的方式构造此代码?

1 个答案:

答案 0 :(得分:2)

您必须明确地跟踪剩余的工作,或许是这样:

(defn f [coll]
  (letfn [(go [xs q]
            (lazy-seq
             (cond
               (seq xs)
               (cons (first xs)
                     (go (next xs) (conj q (explode (first xs)))))
               (seq q)
               (go (peek q) (pop q)))))]
    (go coll clojure.lang.PersistentQueue/EMPTY)))

来自REPL:

(nth (f [1 2 3]) 1000)
;= 3
(nth (f [1 2 3]) 10000)
;= 2

;; f-orig is f as found in the question text
(= (take 1000 (f-orig [1 2 3])) (take 1000 (f [1 2 3])))
;= true