clojure尾递归中的java.lang.StackOverflowError

lka*_*htz 5 stack-overflow reverse loops list clojure

我遇到以下代码的StackOverflowError:

(defn recursive-reverse
  ([coll] (recursive-reverse [coll nil]))
  ([coll acc]
    (if (= coll '()) acc
        (recur (rest coll) (cons (first coll) acc)))))
Run Code Online (Sandbox Code Playgroud)

尽管使用循环会使它工作:

(defn recursive-reverse [lst]
  (loop [coll lst acc nil]
    (if (= coll '()) acc
        (recur (rest coll) (cons (first coll) acc)))))
Run Code Online (Sandbox Code Playgroud)

没有循环的先前代码出了什么问题?

man*_*nge 7

你的错误在这里:

([coll] (recursive-reverse [coll nil]))
Run Code Online (Sandbox Code Playgroud)

recursive-reverse用一个参数(向量)调用.这会调用函数的相同参数列表,因此它会递归执行并每次创建一个堆栈帧.

将其更改为:

([coll] (recursive-reverse coll nil))
Run Code Online (Sandbox Code Playgroud)

你应该是对的.

(另外,单独的问题,但我通常会检查nil而不是'()使用next而不是使用rest.我不认为它在性能或任何方面有任何实际优势,但对我来说似乎更清晰.)

  • `(nil?x)`可能比`(= x())`快得多,因为编译器只能发出一个字节码操作,即Java使用的原始空检查.当然,后者非常快,但我怀疑它比前者慢几倍.实际上,这个优化的nil-check没有实现(但是?),但这是最终可能进行的合理优化. (3认同)