我一直在尝试实现 chainl1 的尾递归版本,但即使使用循环递归它也会引发 StackOverflowError。这怎么可能,我能做些什么来改变它?
(defn atest [state]
(when-not (and (= "" state) (not (= (first state) \a)))
(list (first state) (. state (substring 1)))))
(defn op [state]
(when-not (and (= "" state) (not (= (first state) \a)))
(list #(list :| %1 %2) (. state (substring 1)))))
(defn chainl1-helper [x p op]
(fn [state]
(loop [x x
state state]
(if-let [xs (op state)]
(when-let [xs2 (p (second xs))]
(recur ((first xs) x (first xs2)) (second xs2)))
(list x state)))))
(defn chainl1 [p op]
(fn [state]
(when-let [[v s] (p state)]
((chainl1-helper v p op) s))))
(def test-parse (chainl1 atest op))
(defn stress-test [n] (test-parse (apply str (take n (interleave (repeat "a") (repeat "+"))))))
(stress-test 99999)
最佳答案
它打印的最终结果是堆栈
所以这是 REPL 不是你的代码。
将最后一行替换为
(count (stress-test 99999))
它完成了
堆栈跟踪有这种模式重复多次:
13: core_print.clj:58 clojure.core/print-sequential
14: core_print.clj:140 clojure.core/fn
15: MultiFn.java:167 clojure.lang.MultiFn.invoke
编辑:LDomagala 指出打印级别是防止此类崩溃的安全措施
user> (set! *print-level* 20)
20
user> (stress-test 9999)
((:f (:f (:f (:f (:f (:f (:f (:f (:f (:f (:f (:f (:f (:f (:f (:f (:f (:f (:f # \a) \a) \a) \a) \a) \a) \a) \a) \a) \a) \a) \a) \a) \a) \a) \a) \a) \a) \a) "")
user>
关于clojure - loop-recur 怎么可能抛出 StackOverflowError?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10237880/