8

“纯递归”在这里是一个虚构的术语,请原谅。

这是使用两种不同递归方法的两个示例。一个比另一个的使用指南是什么?

(defn take-while
  "Returns a lazy sequence of successive items from coll while
  (pred item) returns true. pred must be free of side-effects."
  {:added "1.0"
   :static true}
  [pred coll]
  (lazy-seq
   (when-let [s (seq coll)]
       (when (pred (first s))
         (cons (first s) (take-while pred (rest s)))))))

(defn take-last
  "Returns a seq of the last n items in coll.  Depending on the type
  of coll may be no better than linear time.  For vectors, see also subvec."
  {:added "1.1"
   :static true}
  [n coll]
  (loop [s (seq coll), lead (seq (drop n coll))]
    (if lead
      (recur (next s) (next lead))
      s)))
4

3 回答 3

9

需要考虑的几个因素:

  • 循环/递归不消耗堆栈空间- 因此,如果您要进行深度嵌套递归,否则它是正确的选择,否则可能会导致StackOverflowError
  • loop/recur 更快- 它是 Clojure 中最有效的构造之一,正确完成它应该与 Java 代码中等效 for 循环的速度相匹配
  • 普通递归更惯用- 平均而言,它倾向于为您提供更清晰、更具功能性的代码,而循环/递归倾向于将您推向命令式、迭代式风格
  • 循环/递归有更多的限制——你只能在尾部位置递归,你不能在两个不同的函数之间进行相互递归,等等。有时根本不可能使循环/递归工作,在其他时候你可能需要扭曲你的代码来做到这一点。
于 2013-01-11T06:04:01.520 回答
2

lazy-seq使用/lazy-cons机制的唯一原因是生成惰性序列。如果您不需要它们,那么loop/recur无疑应该使用。

于 2013-01-11T07:23:46.447 回答
1

首先在编写函数时使用普通递归。如果可以的话,一旦一切正常,然后将其更改为重复出现。

TCO 的一个问题是,如果你阻止递归,你会得到无限的外观。如果没有,您的代码会因堆栈溢出而崩溃,这正是您想要的。当我第一次听说它时,我不喜欢 recur 的想法——大多数优化应该只是发生——但是能够将其关闭是很好的。

于 2013-01-11T10:16:02.760 回答