clojure - loop-recur 怎么可能抛出 StackOverflowError?

标签 clojure tail-recursion

我一直在尝试实现 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/

相关文章:

vector - clojure解构向量的向量以返回每个向量

c - 使用递归从列表中的最后一个元素查找第 n 个元素

python - 是回文吗?使用不变编程

c++ - g++中的尾递归问题

clojure - 使用 clojure 作为脚本语言时如何添加 Java 实例作为上下文?

clojure - 使用 postwalk 将节点添加到树

regex - 如何在 Clojure 中使用正则表达式过滤目录列表

clojure - 使用 var-quote 语法调用 Clojure 函数

recursion - Prolog 累加器。它们真的是 "different"概念吗?

scala - 评估职能绩效