Recursion 何时使用纯递归,何时使用循环/递归?
“纯递归”在这里是一个虚构的术语,请原谅 下面是两个使用两种不同递归方法的示例。使用一个或另一个的指导原则是什么Recursion 何时使用纯递归,何时使用循环/递归?,recursion,clojure,Recursion,Clojure,“纯递归”在这里是一个虚构的术语,请原谅 下面是两个使用两种不同递归方法的示例。使用一个或另一个的指导原则是什么 (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]
(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)))
需要考虑的几个因素:
- 循环/递归不会占用堆栈空间-因此,如果要执行深度嵌套的递归,则这是正确的选择,否则可能会导致
堆栈溢出错误
- 循环/重现速度更快-它是Clojure中最有效的构造之一,正确完成后,它应该与Java代码中的等效for循环速度相匹配
- 普通递归更惯用——一般来说,它倾向于为您提供更清晰、更实用的代码,而循环/递归则倾向于将您推向命令式、迭代式的风格
- 循环/递归有更多限制-您只能在尾部位置进行递归,不能在两个不同的函数之间进行相互递归,等等。有时循环/递归无法工作,有时可能需要扭曲代码才能工作
- 使用
lazy-seq
/lazy-cons
机制的唯一原因是生成惰性序列。如果您不需要它们,那么毫无疑问应该使用循环
/递归
。当您首先编写函数时,请使用普通递归。然后,如果可以的话,将其更改为在所有操作都正常后重新出现
TCO的一个问题是,如果你阻止递归,你会得到一个无限的外观。如果没有,代码会很好地崩溃,并出现堆栈溢出,这正是您想要的。当我第一次听说它的时候,我不喜欢它的出现——大多数的优化都应该发生——但是能够关闭它是很好的 我真的不明白你在说什么。在第一个示例中,您根本无法选择循环/重复方式,因为
take而不在尾部位置使用。有什么问题?循环/递归总是比函数递归调用更好,并且@mikera解释了原因。编译器不可能将take while中形式的惯用递归(递归是最后一个)转换为循环/递归形式(或它为循环/递归形式生成的代码)?@Hendekagon:在这种情况下,因为递归不在尾部位置。理论上,它可以在其他情况下使用,但我相信Rich Hickey的设计决策是不自动执行此操作-因此,如果您想要尾部递归,您必须使用recur