Recursion 在Clojure函数中获取堆栈溢出。

Recursion 在Clojure函数中获取堆栈溢出。,recursion,clojure,Recursion,Clojure,为什么在以下Clojure函数中出现堆栈溢出: (defn length [xs] (if ,(not= xs nil) (println (+ 1 (length (rest xs)))) (println 0))) 切换到所有惰性seq后,rest将永远不会返回nil,只是一个空列表-尝试以下操作: (defn length [xs] (if (not (empty? xs)) (println (+ 1 (length (rest xs)

为什么在以下Clojure函数中出现堆栈溢出:

(defn length
  [xs]
  (if ,(not= xs nil)
    (println (+ 1 (length (rest xs))))
    (println 0)))

切换到所有惰性seq后,rest将永远不会返回nil,只是一个空列表-尝试以下操作:

(defn length 
   [xs]
   (if (not (empty? xs))
      (println (+ 1 (length (rest xs))))
      (println 0)))
还是这个

(defn length
   [xs]
   (if ,(not= xs nil)
      (println (+ 1 (length (next xs))))
      (println 0)))

我认为这样做的惯用方法是对您的收藏调用
seq
<如果集合为空,则集合上的code>seq返回
nil

(defn length [xs]
  (if (seq xs)
      (inc (length (rest xs)))
      0))
这不是尾部递归(您没有使用
recur
,在这里不能),因此这仍然会在非常大的集合上溢出堆栈

user> (println (length (range 1000000)))
;; stack overflow
单尾递归版本将是

(defn length [xs]
  (loop [xs xs
         acc 0]
    (if (seq xs)
        (recur (rest xs) (inc acc))
        acc)))

user> (println (length (range 1000000)))
1000000

即使是对于大型集合,这也不会溢出堆栈,但仍然很慢。许多Clojure集合实现了
Counted
接口,内置的
count
函数以恒定时间返回这些集合的长度。

您不会谈论StackOverflow上的堆栈溢出。Lol不知道clojure,但当xs只有1个元素时,“rest xs”会返回nil吗?或者它会返回一个空的list/string/任何不是nil的东西吗?我假设堆栈只是溢出了预期的结果。Clojure不会自动优化尾部调用(虽然这不是尾部调用,但可以简单地重写为尾部调用)。我也很难相信这是在函数式语言中实现长度函数的最佳方法,在我看来,它的性能非常差。