loop/recur 和 recur 本身有什么区别?
What is the difference between loop/recur and recur by itself?
我在 Clojure 文档中找不到这个问题的答案。我是 Clojure 的新手,您似乎可以用两种不同的方式使用 recur
并获得相同的结果。
示例 1:
(defn my-function [num]
(if (> num 10)
num
(recur (+ num 1))))
示例 2:
(defn my-function [num]
(loop [cnt num]
(if (> cnt 10)
cnt
(recur (+ cnt 1)))))
据我所知,这两种形式似乎做同样的事情。我知道 recur
之所以好的一般是因为在适当的情况下,编译器可以将某种伪尾调用优化组合在一起,我真的很喜欢并且愿意尽可能多地使用它.所以这是我的问题:
- 当
recur
似乎没有它时,使用 loop
有什么必要?
- 是否
loop
只是创建一个 "recursion scope" 有点像 let
创建迷你范围的方式?
- 如果是这样,我仍然可以在不使用
loop
的情况下获得尾递归的好处吗?
只为一一解答您的问题:
loop
允许您接受和传递任意参数。如果没有 loop
,您将只能传递函数接受的内容。它会导致一堆微小的辅助功能
是的,有点像
一定是尾调用,受编译器约束
- 从不 需要使用
loop
。你可以总是替换它
调用匿名 fn
表单。
- 是的。
loop
作为 let
兼作递归点
recur
。如果 loop
没有捕获到 recur
,您可以将其替换为
let
,反之亦然。
- 是的。
recur
实现了尾递归(而且只有尾递归
递归),无论它递归为 loop
还是 fn
形式。
为了说明(1),可以将例2中的loop
形式替换
(loop [cnt num]
(if (> cnt 10)
cnt
(recur (+ cnt 1))))
...与
((fn [cnt] (if (> cnt 10) cnt (recur (+ cnt 1)))) num)
... 如您所见,它创建并调用了一个匿名函数。
您甚至可以将 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
这可能比正确的 clojure.core/loop
慢。
我在 Clojure 文档中找不到这个问题的答案。我是 Clojure 的新手,您似乎可以用两种不同的方式使用 recur
并获得相同的结果。
示例 1:
(defn my-function [num]
(if (> num 10)
num
(recur (+ num 1))))
示例 2:
(defn my-function [num]
(loop [cnt num]
(if (> cnt 10)
cnt
(recur (+ cnt 1)))))
据我所知,这两种形式似乎做同样的事情。我知道 recur
之所以好的一般是因为在适当的情况下,编译器可以将某种伪尾调用优化组合在一起,我真的很喜欢并且愿意尽可能多地使用它.所以这是我的问题:
- 当
recur
似乎没有它时,使用loop
有什么必要? - 是否
loop
只是创建一个 "recursion scope" 有点像let
创建迷你范围的方式? - 如果是这样,我仍然可以在不使用
loop
的情况下获得尾递归的好处吗?
只为一一解答您的问题:
loop
允许您接受和传递任意参数。如果没有loop
,您将只能传递函数接受的内容。它会导致一堆微小的辅助功能是的,有点像
一定是尾调用,受编译器约束
- 从不 需要使用
loop
。你可以总是替换它 调用匿名fn
表单。 - 是的。
loop
作为let
兼作递归点recur
。如果loop
没有捕获到recur
,您可以将其替换为let
,反之亦然。 - 是的。
recur
实现了尾递归(而且只有尾递归 递归),无论它递归为loop
还是fn
形式。
为了说明(1),可以将例2中的loop
形式替换
(loop [cnt num]
(if (> cnt 10)
cnt
(recur (+ cnt 1))))
...与
((fn [cnt] (if (> cnt 10) cnt (recur (+ cnt 1)))) num)
... 如您所见,它创建并调用了一个匿名函数。
您甚至可以将 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
这可能比正确的 clojure.core/loop
慢。