Recursion 与Clojure和Clojure一起递归,为勇敢和真实的人

Recursion 与Clojure和Clojure一起递归,为勇敢和真实的人,recursion,clojure,Recursion,Clojure,我正在努力学习用这本书编程(CFTBAT)。在速成课程的最后,作者让我们写一个小程序来说明Clojure中的循环。为了解释程序的循环和递归部分,作者使用loop编写了一个较小的示例,然后展示了用普通函数定义替换loop的可能性 这是一个我无法理解的普通函数定义示例。代码如下: (defn递归打印机 ([] (递归打印机(0)) ([迭代] (println迭代) (如果(>迭代3) (打印“再见!”) (递归打印机(包括迭代(()()))) (递归打印机) 我不理解代码,因为我看不到函数递归打

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

这是一个我无法理解的普通函数定义示例。代码如下:

(defn递归打印机
([]
(递归打印机(0))
([迭代]
(println迭代)
(如果(>迭代3)
(打印“再见!”)
(递归打印机(包括迭代(()())))
(递归打印机)
我不理解代码,因为我看不到函数
递归打印机的参数在哪里。在Clojure中,函数的参数应该放在括号中,函数体应该放在括号中。因此,在本例中,参数将是一个空参数
[]
迭代
。但是为什么它们也被放在括号中呢

什么是
(递归打印机0)
它是一个函数调用,函数在其中调用自己吗


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

我们可以放弃零算术:

(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))))
。。。具有完全相同的效果


我认为,额外的算术只是把事情弄糊涂了

在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)
调用(递归打印机)时,它调用第一个表单(零参数) 形式)。该表单依次调用单参数为0的函数。这 调用第二种形式

第二个表单首先打印参数,然后测试它是否正确 大于3,在第一次调用中它不是0,因此它执行 'else'语句,该语句使用新参数执行递归调用,新参数是 当前参数增加了1。现在你的论点是1,它被打印出来了 出来测试仍然为false,因为1不大于3,因此再次调用该函数 论点增加了1,即2。在这个调用中,2被打印,测试被取消 仍然不大于3,因此将使用参数再次调用该函数 增加到3。在这个调用中,打印了3,并且测试仍然不是>3,因此 参数增加到4,并再次调用函数,以4作为 论点打印值4,但这次4大于3,因此字符串“Bye”为 已打印,由于这是终止条件,因此不需要进一步的递归调用
make,堆栈展开,函数终止

有两个不同的参数列表。一个是
[]
,用代码处理调用时没有参数的情况,另一个是
[迭代]
,处理调用时只有一个参数的情况。顺便说一句,由于这本书是在线的,所以有一个链接可能没什么坏处——网络版不是逐页定向的,所以“第63页”对经常使用它的人没有帮助。请参阅第3章“Arity重载”:@CharlesDuffy我编辑了这个问题以添加链接。谢谢,我错过了算术重载!因此,如果在没有参数的情况下调用问题,函数将使用参数(0)调用自身,并将此参数加入到
迭代
中,直到它达到4?这是完全正确的。我认为作者想展示一个不使用
循环
递归
的递归示例。