【问题标题】:How is it possible that loop-recur throws a StackOverflowError?loop-recur 怎么可能抛出 StackOverflowError?
【发布时间】:2012-04-20 07:21:49
【问题描述】:

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

【问题讨论】:

    标签: clojure tail-recursion


    【解决方案1】:

    它打印出堆栈的最终结果 所以这是 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 指出 print-level 是针对此类崩溃的安全措施

    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> 
    

    【讨论】:

    • 我被告知您也可以使用 (set!print-level 20),这样只有部分结果会被打印,而堆栈不会被破坏。
    猜你喜欢
    • 2016-02-22
    • 1970-01-01
    • 2012-03-04
    • 1970-01-01
    • 2015-10-28
    • 2012-04-29
    • 1970-01-01
    • 2020-02-24
    • 1970-01-01
    相关资源
    最近更新 更多