【问题标题】:What is the difference between loop/recur and recur by itself?loop/recur 和 recur 本身有什么区别?
【发布时间】:2016-02-22 12:12:14
【问题描述】:

我在 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 好的原因通常是在适当的情况下,编译器可以将某种伪尾调用优化组合在一起,我真的很喜欢并且希望尽可能多地使用它。所以这是我的问题:

  1. 如果没有 recur 似乎也可以工作,那么使用 loop 有什么需要?
  2. loop 是否只是创建一个类似于let 创建迷你范围的“递归范围”?
  3. 如果是这样,不使用loop,我还能获得尾递归的好处吗?

【问题讨论】:

  • 使用loop,您可以接受(并传递)任意组参数,如果没有loop,您只能传递可以接受的函数。
  • 这是有道理的。我相信可以回答问题1和2。那么第三个呢?
  • 必须是尾调用,否则无法编译。
  • 你的例子很可疑。您应该在两者中都有if 而不是when。我冒昧地纠正了它们(我希望!),
  • @Thumbnail 感谢代码编辑。正如我所说,我是 Clojure 的新手。不过,请问您什么时候适合使用when 而不是if

标签: recursion clojure tail-recursion tail-call-optimization


【解决方案1】:

只是一一回答你的问题:

  1. loop 允许您接受和传递任意参数。如果没有loop,您将受到限制,只能通过函数接受的内容。它会导致一堆微小的辅助功能

  2. 是的,有点

  3. 必须是尾调用,受编译器约束

【讨论】:

    【解决方案2】:
    1. 从不需要使用loop。你可以总是替换它 致电匿名fn 表单。
    2. 是的。 loop 充当 let,它兼作递归点 recur。如果 loop 没有捕获到 recurs,您可以将其替换为 let,反之亦然。
    3. 是的。实现尾递归的是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 慢。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2023-03-14
      • 2011-04-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-07-30
      • 1970-01-01
      相关资源
      最近更新 更多