使用递归测试(条件)添加连续的整数

Add successive integers with recursive tests (conditionals)

我的递归函数正确地对 ab 之间的所有整数求和,包括在内。但是,当我交换参数时,结果不正确。我正在读 SICP。我的代码是(方案):

 (define (sum-integers a b)
   (if (> a b)
      (if (= (- a 1) b)
       (+ a b)
        (+ a(sum-integers (- a 1) b)))
     (+ a (sum-integers (+ a 1) b))))

     (sum-integers 5 2)
     (sum-integers 2 5)

我确定我的编译器是applicative order,所以我认为输出应该是一样的。

      (sum-integers 5 2)
      (sum-integers 2 5)

事实上,

  (sum-integers 5 2) ==> 14
  (sum-integers 2 5) ==> 25

但是 2+3+4+5 = 5+4+3+2 = 14.

为什么我的结果不同?

当您发送 5,2 与 2,5 时,条件 if (> a b) 会创建不同的流程:

当您发送 a=5,b=2 时,这意味着 a > b 所以我们将进入 if,并且由于 5-1 > 2 递归调用将是 (+ a(sum-integers (- a 1) b)).

当您发送 a=2, b=5 时,条件 if (> a b) 将 return 为假,递归调用将是最后一行:(+ a (sum-integers (+ a 1) b))

如您所见:
(+ a (sum-integers (- a 1) b)) 不同于:
(+ a (sum-integers (+ a 1) b))

难怪你会得到不同的结果。

在显示错误的第二个测试用例中,循环直到 a = 6b = 5 才终止。然后它在总数 14 的基础上再加上 6 和 5,得到 25。

您发现这个错误很难找到的原因可能是因为代码比它可能的更复杂,或者因为您还没有学会如何跟踪递归代码。

我还注意到你的代码缩进不一致。让您的编辑器为您缩进代码,以帮助您遵循逻辑。

我已经编写了评论中提到的设计@alfasin 的代码。您可以看到简单性使得调试更容易。如果 a > b 那么我们只是交换参数并像以前一样继续。

我认为思考这个问题的关键是确保你想要重复的操作(这里是加法)在你的函数中只出现一次。

(define (sum2-integers a b)
  (if (> a b)
    (sum2-integers b a)   ; if the wrong way round, swap them
    (if (= a b)           ; termination condition
       b
       (+ a (sum2-integers (+ a 1) b)))))

> (sum2-integers 5 2)
14
> (sum2-integers 2 5)
14

进一步简化。我发现多路条件分支 cond 比嵌套 if 更具可读性,因为这段代码中确实有三个分支。

(define (sum3-integers a b)
  (cond [(> a b) (sum3-integers b a)]
        [(= a b) b]
        [else (+ a (sum3-integers (+ a 1) b))]))