使用递归测试(条件)添加连续的整数
Add successive integers with recursive tests (conditionals)
我的递归函数正确地对 a
和 b
之间的所有整数求和,包括在内。但是,当我交换参数时,结果不正确。我正在读 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 = 6
和 b = 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))]))
我的递归函数正确地对 a
和 b
之间的所有整数求和,包括在内。但是,当我交换参数时,结果不正确。我正在读 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 = 6
和 b = 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))]))