Recursion 方案:过程是递归的,但过程是递归的还是迭代的?

Recursion 方案:过程是递归的,但过程是递归的还是迭代的?,recursion,scheme,lisp,r5rs,Recursion,Scheme,Lisp,R5rs,所以我不确定我是否最终理解了它,或者我仍然错了。是否正确: (define (add-one x) (+ x 1)) (define (sub-one x) (- x 1)) (define (add-numbers x y) (if (zero? y) x (add-numbers (add-one x) (sub-one y)))) 。。。添加数字是一个递归过程和一个递归过程和 (define (add-numbers2 x y)

所以我不确定我是否最终理解了它,或者我仍然错了。是否正确:

(define (add-one x)
  (+ x 1))

(define (sub-one x)
  (- x 1))

(define (add-numbers x y)
  (if (zero? y)
          x
          (add-numbers (add-one x) (sub-one y))))
。。。添加数字是一个递归过程和一个递归过程和


(define (add-numbers2 x y)
  (if (zero? y)
          x
          (add-numbers2 (+ x 1) (- y 1))))
。。。add-numbers2是一个递归过程和一个迭代过程?

这两个过程在语法上都是递归的,但都会生成迭代计算过程。在第一个函数中:

(define (add-numbers x y)
  (if (zero? y)
          x
          (add-numbers (add-one x) (sub-one y))))
然后,如果
y
不为零,则需要计算
(添加数字(添加一个x)(子一个y))
,为此需要调用
(添加一个x)
(添加一个y)
,然后对两个结果调用
添加数字
,整个函数的结果是调用
addnumbers
返回的结果。重要的是,对
添加数字的调用是最后发生的事情。不需要返回到函数调用时的点,因为除了返回计算值之外,没有其他事情要做。这意味着这个过程是迭代的

在第二个版本中:

(define (add-numbers2 x y)
  (if (zero? y)
          x
          (add-numbers2 (+ x 1) (- y 1))))
要想知道这是一样的,最简单的方法是认识到
+
-
只是函数,所以这是完全一样的!唯一的区别是
+
-
恰好是由实现定义的函数,而不是由您定义的函数

这是一个真正描述递归计算过程的版本:

(define (add-numbers3 x y)
  (if (zero? y)
      x
      (+ 1 (add-numbers3 x (- y 1)))))
在此版本中,如果
y
不是零,则函数必须调用
x
,并从
y
中减去1的结果。。。然后,一旦这样做了,它仍然需要将1添加到该调用的结果中。因此,它需要保留一个内存,以确保有一个添加1的挂起操作,然后当它从该函数调用返回时,实际执行该添加操作。使用原始函数可能更容易看到这一点:

(define (add-numbers4 x y)
  (if (zero? y)
      x
      (add-one (add-numbers4 x (sub-one y)))))

现在您可以清楚地看到,当对
add-numbers4
的递归调用返回时,还有更多的工作要做。

@tb解释说,这两个过程都是迭代的,这是正确的。我们可以把这个过程想象成-

(add-numbers 3 5)
(add-numbers 4 4)
(add-numbers 5 3)
(add-numbers 6 2)
(add-numbers 7 1)
(add-numbers 8 0)
8
看看它如何保持漂亮和平坦?这是一个线性过程。只要稍加修改,我们就能产生一个完全不同的过程-

(define (add-numbers x y)
  (if (zero? y)
      x
      (+ 1 (add-numbers x (- y 1))))
(add-numbers 3 5)
(+ 1 (add-numbers 3 4))
(+ 1 (+ 1 (add-numbers 3 3)))
(+ 1 (+ 1 (+ 1 (add-numbers 3 2))))
(+ 1 (+ 1 (+ 1 (+ 1 (add-numbers 3 1)))))
(+ 1 (+ 1 (+ 1 (+ 1 (+ 1 (add-numbers 3 0))))))
(+ 1 (+ 1 (+ 1 (+ 1 (+ 1 3)))))
(+ 1 (+ 1 (+ 1 (+ 1 4))))
(+ 1 (+ 1 (+ 1 5)))
(+ 1 (+ 1 6))
(+ 1 7)
8
请注意,随着依赖值的计算,过程是如何深化的,直到它最终崩溃为返回值。这是一个递归过程-

(define (add-numbers x y)
  (if (zero? y)
      x
      (+ 1 (add-numbers x (- y 1))))
(add-numbers 3 5)
(+ 1 (add-numbers 3 4))
(+ 1 (+ 1 (add-numbers 3 3)))
(+ 1 (+ 1 (+ 1 (add-numbers 3 2))))
(+ 1 (+ 1 (+ 1 (+ 1 (add-numbers 3 1)))))
(+ 1 (+ 1 (+ 1 (+ 1 (+ 1 (add-numbers 3 0))))))
(+ 1 (+ 1 (+ 1 (+ 1 (+ 1 3)))))
(+ 1 (+ 1 (+ 1 (+ 1 4))))
(+ 1 (+ 1 (+ 1 5)))
(+ 1 (+ 1 6))
(+ 1 7)
8

我想说它们都是递归调用,但第一个是尾部递归调用,这意味着它可以在不需要堆栈增长的情况下执行。但是函数调用仍然是递归的。@OliverMason:OP的两个示例都是尾部递归的,这就是为什么它们都生成迭代过程(而不是调用)。我的最后一个示例不是tail recursive,因此生成了一个递归过程。wups,只是保留了一些草稿文本:D