Recursion add1在这个球拍节目中是如何使用的?

Recursion add1在这个球拍节目中是如何使用的?,recursion,scheme,lisp,racket,Recursion,Scheme,Lisp,Racket,我试图理解add1在这个递归示例中是如何使用的: (define (my-length a-list) (if (empty? a-list) 0 (add1(my-length (rest a-list))))) 如果给定(我的列表(1234))程序将返回数字4 我知道每次迭代函数my lengh后,代码都会分解列表,直到列表为空。我不明白的是,(add1)如何将每次迭代添加到函数中。add1将1添加到其参数并返回该和。因此,如果列表其余部分的长度为3,(add1

我试图理解add1在这个递归示例中是如何使用的:

(define (my-length a-list)
  (if (empty? a-list)
      0
      (add1(my-length (rest a-list)))))
如果给定
(我的列表(1234))
程序将返回数字4


我知道每次迭代函数
my lengh
后,代码都会分解列表,直到列表为空。我不明白的是,
(add1)
如何将每次迭代添加到函数中。

add1
1
添加到其参数并返回该和。因此,如果列表其余部分的长度为
3
(add1(我的长度(rest a-list))
1
添加到
3
并返回
4

在空列表的基本情况下,
my length
返回
0

(my length'(4))
调用递归中的
(my length'())
,返回
0
,然后调用
add1
,返回
1

(my length'(34))
调用递归中的
(my length'(4))
。如上所述,它返回
1
,然后对此调用
add1
,后者返回
2


等等。

如果您的问题是递归,我建议您
跟踪
my length
的重复调用。 例如,在DrRacket中,在定义窗口中写入以下内容:

#lang racket

(require racket/trace)

(define (my-length a-list)
  (if (empty? a-list)
      0
      (add1(my-length (rest a-list)))))

(trace my-length)
(my-length '(a b c d))
点击
Run
并观察:

>(my-length '(a b c d))
> (my-length '(b c d))
> >(my-length '(c d))
> > (my-length '(d))
> > >(my-length '())
< < <0
< < 1
< <2
< 3
<4
4
>(我的长度(a b c d))
>(我的长度(b c d))
>>(我的长度(c d))
>>(我的长度(d))
>>>(我的长度'())

<评估如下:

   (my-list '(1 2 3 4))
-> (add1 (my-list '(2 3 4)))
-> (add1 (add1 (my-list '(3 4))))
-> (add1 (add1 (add1 (my-list '(4)))))
-> (add1 (add1 (add1 (add1 (my-list '())))))
-> (add1 (add1 (add1 (add1 0))))
-> (add1 (add1 (add1 1)))
-> (add1 (add1 2))
-> (add1 3)
-> 4

为了另一种解释:

这就是我们的出发点

(my-length '(a b c d))
通过将参数填充到函数中,这将变成

(if (empty? '(a b c d))
  0
  (add1 (my-length (rest '(a b c d)))))
显然,
”(a b c d)
不是空的。因此,对if的“else”情况进行评估:

(add1 (my-length (rest '(a b c d))))
(add1 (my-length '(b c d)))
现在,我的长度是什么意思?如果我们将函数体复制粘贴到最后一行,我们会得到:

(add1 (if (empty? '(b c d))
        0
        (add1 (my-length (rest '(b c d))))))
继续

(add1 (add1 (my-length (rest '(b c d)))))
(add1 (add1 (my-length '(c d))))
这将继续,直到我们得到一个空列表:

(add1 (add1 (add1 (add1 (if (empty? '())
                              0
                              (add1 (my-length (rest '()))))))))
”()
为空,因此if语句返回0:

(add1 (add1 (add1 (add1 0))))
(add1 (add1 (add1 1)))
(add1 (add1 2))
(add1 3)
4
这就像我们越来越深入地研究函数,因为对于我们采取的每一步,我们都需要再做一步来实际评估我们所拥有的


这与
(add1'(a b c d))有何不同?从评估结果可以看出,
add1
从未实际应用于a、b、c或d。我们甚至从未检查过清单上有什么。你可以有一个由四个列表组成的列表,每个列表都包含列表列表,它的计算结果都是一样的

具体来说,说
(add1'(a b c d))
就像说“1加草莓是什么?”而你的函数更像:

“此列表中有多少项?”

“好吧,如果你没有在上面看到任何东西(
(首先是我的列表)
),那么肯定没有。”

“好吧,好吧……我看到一个“a”在上面!”

“太好了!把它拿出来。名单上至少有一个。”

“好吧,但剩下的有多少?”

我们再试一次怎么样?只要继续从列表顶部取出项目,直到列表为空。然后,我们将把它放回一起,边走边计数

“好的,我把它们都拿出来了。我现在要把它们放回去:d,那是1;c,那是2;b,那是3;a,那是4!”


“好了,列表中有4个!”

我仍然很难想象是什么让计数器保持了多少次(add1)的迭代。在上一个示例中,您说它返回1是因为返回了0,(我的列表)如何得到0?如果代码一直迭代,直到给我的列表的列表为空,这是否意味着(empty?a-list)将返回0,因此退出代码?似乎您不理解递归。每个子列表都是对
my length
的单独调用。它返回一个长列表调用的值。我真的不知道,我是编程的初学者。我通常会在我最初的帖子中解释这一点,但有时会被删掉,所以我开始不这么做。我目前正在使用“球拍王国”。我上过一些基本的编程课,但仍然很难理解某些概念,比如递归,这对我来说是非常新的。如果你仍然不懂,我建议你回到课本上,重新阅读关于递归的部分。这是所有程序员都需要理解的一个重要概念。我现在是。在我对这些概念有了一个有用的理解之前,我通常会一直坚持我不理解的概念。出于某种原因,我正在经历一段难以置信的艰难时期,试图理解这一点。我很感激你为帮助初学者所做的努力。我认为其他答案足以回答这个问题,但根据你的评论,我想知道这是否有帮助:
(add1…====(+1…
)。因此,
(长度l)==(+1(长度(剩余l))
如果
l
是非空列表,而
0
如果
l
是空列表。因此
(length'(x y z))===(+1(+1(+10)))===3
。这与本书中给出的解释相同。我仍然很难理解(add1)是如何在列表的每次迭代中重复出现的,而不会因为尝试向列表中添加数字而在开始时抛出错误。如果我创建一个列表,比如(define a-lista'(1234)),然后尝试将1添加为(add1 a-lista),那么只会给我一个错误。那么,它为什么不在我的列表在其内部级别进行评估的同时进行评估呢?@Alex_adl04您是对的,
(add1'(1 2 3 4))
将是一个错误。幸运的是,这种情况从未发生过。如果参数是
(1234)
,那么您将计算
If
的其他部分,即
(add1(我的长度(rest'(1234)))
。不用担心它是如何工作的,您应该看到
(我的长度(rest'(1234))
应该返回
3
。如果是这样,那么您最终会调用