以@A.Webb 的回答和@amalloy 的评论为基础:
recur
不是调用函数的简写,也不是函数。这是执行尾调用优化的一种特殊形式(在另一种语言中您将称之为语法)。
尾调用优化是一种允许在不破坏堆栈的情况下使用递归的技术(没有它,每个递归调用都会将其调用帧添加到堆栈中)。它还没有在 Java 中本地实现,这就是为什么recur
在 Clojure 中用于标记尾调用的原因。
递归使用lazy-seq
是不同的,因为它通过将递归调用包装在闭包中来延迟递归调用。这意味着对根据(尤其是此类函数中的每个递归调用)实现的函数的调用lazy-seq
(尤其是此类函数中的每个递归调用)会(立即)返回一个LazySeq
序列,该序列的计算被延迟,直到它被迭代。
为了说明和限定@amalloy 的评论recur
和懒惰是相互排斥的,这里有一个filter
使用这两种技术的实现:
(defn filter [pred coll]
(letfn [(step [pred coll]
(when-let [[x & more] (seq coll)]
(if (pred x)
(cons x (lazy-seq (step pred more))) ;; lazy recursive call
(recur pred more))))] ;; tail call
(lazy-seq (step pred coll))))
(filter even? (range 10))
;; => (0 2 4 6 8)
两种技术都可以用在同一个函数中,但不能用于同一个递归调用;step
如果使用了惰性递归调用,则该函数将无法编译,recur
因为在这种情况下recur
不会处于尾调用位置(尾调用的结果不会直接返回,而是会传递给lazy-seq
)。