为什么我在以下Clojure函数中获得堆栈溢出:
(defn length
[xs]
(if ,(not= xs nil)
(println (+ 1 (length (rest xs))))
(println 0)))
Run Code Online (Sandbox Code Playgroud)
Bri*_*per 10
我认为这样做的惯用方法是调用seq你的收藏. 如果集合为空,则seq返回nil集合.
(defn length [xs]
(if (seq xs)
(inc (length (rest xs)))
0))
Run Code Online (Sandbox Code Playgroud)
这不是尾递归(你没有使用recur,也不能在这里)所以这仍然会在非常大的集合上溢出堆栈.
user> (println (length (range 1000000)))
;; stack overflow
Run Code Online (Sandbox Code Playgroud)
一个尾递归版本
(defn length [xs]
(loop [xs xs
acc 0]
(if (seq xs)
(recur (rest xs) (inc acc))
acc)))
user> (println (length (range 1000000)))
1000000
Run Code Online (Sandbox Code Playgroud)
即使对于大型集合,这也不会溢出堆栈,但它仍然很慢.许多Clojure集合实现了Counted接口,内置count函数以恒定的时间返回这些集合的长度.