【问题标题】:Recursion with Clojure and Clojure for the Brave and True使用 Clojure 和 Clojure 进行递归,用于勇敢和真实
【发布时间】:2017-10-12 21:17:53
【问题描述】:

我正在尝试通过 Clojure for the Brave and True (CFTBAT) 这本书来学习编程。在速成课程的最后,作者让我们编写了一个小程序来说明 Clojure 中的循环。为了解释程序的循环和递归部分here,作者使用loop 编写了一个较小的示例,然后说明可以用普通函数定义替换loop

这是我看不懂的普通函数定义示例。代码如下:

(defn recursive-printer
    ([]
        (recursive-printer 0))
    ([iteration]
        (println iteration)
        (if (> iteration 3)
            (println "Bye!")
            (recursive-printer (inc iteration)))))

(recursive-printer)

我看不懂代码,因为我看不到函数recursive-printer 的参数在哪里。在 Clojure 中,函数的参数应该在括号中,函数体在括号中。因此,在此示例中,参数将是空参数 []iteration。但是为什么还要放在括号之间呢?

(recursive-printer 0)是什么?是函数调用吗,函数调用自己的地方?

如果有人能解释一下这段代码是如何工作的,那将不胜感激。

【问题讨论】:

  • 有两个不同的参数列表。一个[] - 带有用于处理不带参数调用它的情况的代码 - 另一个[iteration] 用于处理带有一个参数的调用。
  • 顺便说一句,因为这本书可以在线获得,所以有一个链接可能不会有什么坏处——网络版不是逐页定向的,所以“第 63 页”没有帮助使用它的人。
  • 参见第 3 章“Arity 重载”:braveclojure.com/do-things
  • @CharlesDuffy 我编辑了问题以添加链接。谢谢,我错过了arity重载!因此,如果在没有参数的情况下调用问题,则该函数会使用参数 (0) 调用自身并包含此参数,iteration直到它达到 4?
  • 完全正确。

标签: recursion clojure


【解决方案1】:

在 clojure 中,您可以定义一个函数,使其可以接受不同数量的 论据,例如

(defn foo []
  ....)

是一个不带参数的函数。它是这样称呼的..

(foo)

(defn foo [x]
  ...)

是一个接受 1 个参数的函数。可以这样称呼

(foo :a)

但有时,您可能想要定义一个取 0 或 1 的函数 争论。为此,您使用稍微不同的格式

(defn foo
  ([] ;no argument form 
    ...)
  ([x] ;single argument form
    ...))

一个常见的习惯是在递归函数定义中使用零参数形式 并包含一个“累加器”参数形式作为主要部分 功能。所以,看看你的例子,你有

(defn recursive-printer
    ([] ; zero argument form
        (recursive-printer 0))
    ([iteration] ; 1 argument form
        (println iteration)
        (if (> iteration 3)
            (println "Bye!")
            (recursive-printer (inc iteration)))))

(recursive-printer)

当您调用 (recursive-printer) 时,它会调用第一种形式(零参数 形式)。该形式反过来调用具有单个参数 0 的函数。这 调用第二种形式。

第二种形式首先打印出参数,然后测试它是否是 大于 3,在第一次调用中它不是 0,所以它执行 'else' 语句,它使用一个新参数进行递归调用,该参数是 当前参数增加了 1。现在你的参数是 1 并且它被打印出来 出去。测试仍然为假,因为 1 不 > 3,因此再次调用该函数 参数增加 1 即 2。在此调用中,打印 2,测试是 仍然不大于 3,所以函数再次使用参数调用 增加到 3。在这个调用中,打印了 3 并且测试仍然不 > 3,所以 参数递增到 4 并再次调用函数以 4 作为 争论。打印值 4,但这次 4 > 3,所以字符串“Bye”是 打印,因为这是终止条件,所以没有进一步的递归调用 made 并且堆栈展开并且函数终止。

【讨论】:

    【解决方案2】:

    我们可以去掉零元:

    (defn recursive-printer [iteration]
      (println iteration)
      (if (> iteration 3)
        (println "Bye!")
        (recursive-printer (inc iteration))))
    

    ...并使用显式 0 参数调用函数:

    (recursive-printer 0)
    0
    1
    2
    3
    4
    Bye!
    => nil
    

    这让我们专注于递归。由于递归调用是最后完成的事情(在尾部位置),我们可以使用 recur 代替:

    (defn recursive-printer [iteration]
      (println iteration)
      (if (> iteration 3)
        (println "Bye!")
        (recur (inc iteration))))
    

    ...效果完全一样。

    我认为,额外的数量只会让事情变得混乱。

    【讨论】:

    • 我认为作者想展示一个不使用looprecur的递归示例。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2015-10-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-03-31
    • 2015-04-05
    • 1970-01-01
    相关资源
    最近更新 更多