res*_*ive 3 recursion tail-recursion clojure tail-call-optimization
我在Clojure文档中找不到答案。我是Clojure的新手,似乎您可以recur两种不同的方式使用并且基本上得到相同的结果。
范例1:
(defn my-function [num]
(if (> num 10)
num
(recur (+ num 1))))
Run Code Online (Sandbox Code Playgroud)
范例2:
(defn my-function [num]
(loop [cnt num]
(if (> cnt 10)
cnt
(recur (+ cnt 1)))))
Run Code Online (Sandbox Code Playgroud)
据我所知,这两种形式似乎做的完全相同。我知道,recur总体上讲,这样做的原因是好的,因为在适当的情况下,编译器可以破解某种伪尾部调用优化方法,我非常喜欢并且希望尽可能多地利用它。所以这是我的问题:
loop如果recur没有它,似乎什么也可以使用?loop仅创建“递归范围”,就像let创建迷你范围一样?loop吗?只是一个接一个地回答您的问题:
loop允许您接受并传递任意参数。如果没有,loop您将只能只接受函数接受的内容。这会导致堆很小的辅助功能
是的,有点
它必须是一个尾部调用,并且受编译器的约束
loop. 您始终可以将其替换为对匿名表单的调用fn。loop充当 alet兼作 的递归点
recur。如果 aloop没有捕获recurs,则可以用 a 替换它
let,反之亦然。recur实现了尾递归(并且仅尾递归),无论它递归到 aloop还是fn表单。为了说明(1),您可以替换loop示例2中的形式
(loop [cnt num]
(if (> cnt 10)
cnt
(recur (+ cnt 1))))
Run Code Online (Sandbox Code Playgroud)
... 和
((fn [cnt] (if (> cnt 10) cnt (recur (+ cnt 1)))) num)
Run Code Online (Sandbox Code Playgroud)
...如您所见,它创建并调用匿名函数。
您甚至可以编写loop为进行此转换的宏:
(defmacro loop [bindings & body]
(let [[names values] (apply map vector (partition 2 bindings))]
`((fn ~names ~@body) ~@values)))
(loop [i 10, ans 0]
(case i
0 ans
(recur (dec i) (+ ans i))))
; 55
Run Code Online (Sandbox Code Playgroud)
这可能比正确的慢clojure.core/loop。