递归函数返回求和,努力理解为什么?

时间:2017-03-06 16:07:04

标签: functional-programming scheme lisp

在评论表上给我以下功能:

(define mystery(lambda(m n)
                 (cond
                   ((= m 0) n)
                   ((= n 0) m)
                   (#t (+ 2(mystery(- m 1)(- n 1))))
                   )))

前两个条件很简单,只是递归otherwise令我感到困惑。在我看来,递归将继续,直到它们都等于零,这肯定不会返回总和。有人可以提供解释吗?

5 个答案:

答案 0 :(得分:2)

首先,让我们更好地格式化代码,看看发生了什么:

(define (mystery m n)
  (cond ((= m 0) n)
        ((= n 0) m)
        (else (+ 2 (mystery (- m 1) (- n 1))))))

现在,请记住,cond仅执行与true的第一个条件相对应的操作(从上到下),其他操作将被忽略。如果所有条件都不是true,则执行else部分。要记住的重要一点是,只执行一个操作。

特别是,当 mysterym变为零时,n程序将停止,而两者变为零时。当其中一个达到零时,递归开始展开,返回总和。跟踪执行时可以看到这一点 - 例如,在Racket中:

(require racket/trace)
(trace mystery)
(mystery 3 2)

>(mystery 3 2)
> (mystery 2 1)
> >(mystery 1 0)
< <1
< 3
<5

答案 1 :(得分:2)

只是详细说明ÓscarLópez的答案(我不能在评论中对此进行格式化):我发现将这些类似的小递归数学函数写成数学通常很有用:

设m和n为自然数,然后

  • n + m = n,如果m = 0;
  • n + m = m,如果n = 0;
  • n + m = n - 1 + m - 1 + 2;
  • 没有其他案例。

答案 2 :(得分:1)

我觉得最好的方法不是筑巢而是预先计算。查看基本情况,我们用零测试:

(mystery 0 2) ; ==> 2
(nystery 3 0) ; ==> 3

因此,每次至少有一个参数为零时,它返回另一个参数。让我们尝试非零值,并记住第二个你看到我们已经完成的值,然后再用它的结果切换它:

(mystery 1 3)        ; ==
(+ 2 (mystery 0 2))  ; == (we switch known value)
(+ 2 2)                        
; ==> 4 

(mystery 4 1)       ; == (we substitute with the expression)
(+ 2 (mystery 3 0)) ; == (we switch known value)
(+ 2 3) 
; ==> 5 

因为我们知道基本情况总是返回另一个值,所以我们不需要预先计算它。这是一个做到这一点:

(mystery 3 9)                  ; == (we substitute with the expression)
(+ 2 (mystery 2 8)             ; == (we substitute with the expression)
(+ 2 (+ 2 (mystery 1 7)))      ; == (we substitute with the expression)
(+ 2 (+ 2 (+ 2 (mystery 0 6))) ; == (we substitute with the expression, n, which is 6)
(+ 2 (+ 2 (+ 2 6)))            ; == (we substitute (+ 2 6))
(+ 2 (+ 2 8))                  ; == (we substitute (+ 2 8))
(+ 2 10)                       ; == (we substitute (+ 2 10)
; ==> 12

我们可以概括将要发生的事情。 nm的最低值将决定递归何时结束。在每一步,它将添加2并递归。因此,它是一种奇特的制作方式:

(define (double-min n m)
 (let ((vmin (min n m))
       (vmax (max n m)))
   (+ (* 2 vmin) (- vmax vmin))))

这又是添加两个数字的一​​种奇特方式,因为如果n > m,那么2*m+(n-m) = m+m+(n-m) = m+n

答案 3 :(得分:0)

(define mystery(lambda(m n)
                 (cond
                   ((= m 0) n)
                   ((= n 0) m)
                   (#t (+ 2 (mystery (- m 1) (- n 1))))
                   )))

第一和第二个条件是显而易见的。

第三条陈述如何运作的说明:

  

1从m和n中取出,并在此函数外保持为2。   这一直持续到m为0或n为0。

答案 4 :(得分:0)

前2个案例很明显,其中一个数字为0的2个数字的总和等于另一个数字。

在最后一种情况下,在检查0的参数后,我们确信它们都是非0。 假设那个谜团返回其2个参数的总和,那么

(+ 2 (mystery (- arg1 1) (- arg2 1)))

将返回一个等于(mystery arg1 arg2)的总和,并在其中一个参数为0时最终停止,返回所需的结果。

假设神秘回归,其两个参数的总和在这里是关键,被称为信仰的递归跳跃。 (谷歌)