方案:SICP 中过程参数的用途:1.3(高阶过程)
Scheme: The purpose of procedure arguments in SICP: 1.3 (Higher Order Procedures)
在 SICP 的 1.3 节中,我们通过引入两个过程作为过程的参数来抽象求和过程。
(define (sum term a next b)
(if (> a b) 0
(+ (term a) (sum term (next a) next b))))
为什么我们不能像这样写同样的程序:
(define (identity a ) a)
(define (next a) (+ a 1)
(define (sum a b)
(if (> a b) 0
(+ (identity a) (sum (next a) b))))
我无法理解在这个特定示例中将过程作为参数传递的原因。
有什么特殊原因吗?还是只是为了演示这个概念?
有更好的例子吗?
就跟你说的一样求和。
如果您学习基础数学,您可能需要计算许多 系列 .
- 1+2+3+...+n
- 1/n+2/n+3/n+...+n/n
- 0+2+3+...+n
- 1^2+2^+3^2+...+n^2
- f(1)+f(2)+f(3)+...+f(n)
- f(1)+f(3)+f(5)+...
我们可以多方面思考。
- 摘要:基本摘要。求和符号我们都在数学课程中学习过。所以不奇怪。
- 修改:在您的第二个版本中,您必须重写所有代码。在第一个版本中不需要。请参阅下面的演示。
- 理解:如果有人看到这样的代码:
(define (1/1+1/2+1/3+...+1/k k) (summation / 1 add1 k))
那么我们只需要将i=1的形式转化为sum of 1/i to i=k(这里是i≤k)就像我们在数学课程中学习它。
- 轻松测试
- extension :也许有一天你想要扩展到向量系列。
如果我们要添加向量系列:vector-1 + vector-2 + ... + vector-n
我们只需要将这个
+
函数(在 sum
内)更改为 add-vector
并添加 if-else
以检查输入是数字还是向量。我们可以设计类似my-inf
这样的东西,这样我们就可以用另一种方式来计算1+2+3+...+inf
.
- 新算法或加速:如果我们谈论
sqrt
,我们都同意这种抽象很重要,因为我们有很多算法来计算 sqrt
。
#lang racket
(define (sum term a next b)
(if (> a b) 0
(+ (term a) (sum term (next a) next b))))
(define (1+2+...+k k)
(sum identity 1 add1 k))
(define (0^2+1^2+2^2+...+k^2 k)
(sum sqr 0 add1 k))
(define (1+3+5+...+k k)
(sum (λ (n) (- (* 2 n) 1)) 1 add1 k))
(define (1/1+1/2+1/3+...+1/k k)
(sum / 1 add1 k))
(define (1/1^2+1/2^2+1/3^2+...+1/k^2 k)
(sum (λ (n) (/ (sqr n))) 1 add1 k))
; sqr(0)+sqr(2)+sqr(4)+sqr(6)
(sum sqr 0 (λ (a) (+ a 2)) 7) ; 56
;;; TEST
(0^2+1^2+2^2+...+k^2 3) ; 14
(1+2+...+k 100) ; 5050
(1+3+5+...+k 5) ; 1+3+5+7+9=25
(1/1+1/2+1/3+...+1/k 5) ; (+ 1/1 1/2 1/3 1/4 1/5) = 2 + 17/60
(1/1^2+1/2^2+1/3^2+...+1/k^2 3) ; (+ 1 1/4 1/9) = 1 + 13/36
将过程作为参数传递的原因是,通过这种方式您可以参数化您的过程,从而改变它的行为。当然,在原始版本中,您可以简单地将所有数字相加,与第二个版本相同:
(define (sum term a next b)
(if (> a b)
0
(+ (term a) (sum term (next a) next b))))
(define (identity a) a)
(define (plus1 a) (+ 1 a))
(sum identity 1 plus1 10)
=> 55
但现在您也可以灵活地计算其他系列,而无需更改原始代码 - 您只需通过不同的程序即可获得不同的结果。比如,你想计算平方和:
(define (square a) (* a a))
(sum square 1 plus1 10)
=> 385
或者您想计算总和,但跳过数字:
(define (plus2 a) (+ 2 a))
(sum identity 1 plus2 10)
=> 25
这就是高阶程序的强大之处:无需更改基本代码即可定制和扩展。而且由于可以以可组合和可重用的方式编写过程,因此您可以非常灵活地考虑计算,而不必一遍又一遍地编写样板代码。
如果你想计算
f(a0) + f(a0+r) + f(a0+2r) + ...
您不能使用第二个表格,但可以使用 SICP 中的表格。 Scheme 可以帮助您以一种很好的方式实现 ∑.
的抽象概念
在 SICP 的 1.3 节中,我们通过引入两个过程作为过程的参数来抽象求和过程。
(define (sum term a next b)
(if (> a b) 0
(+ (term a) (sum term (next a) next b))))
为什么我们不能像这样写同样的程序:
(define (identity a ) a)
(define (next a) (+ a 1)
(define (sum a b)
(if (> a b) 0
(+ (identity a) (sum (next a) b))))
我无法理解在这个特定示例中将过程作为参数传递的原因。
有什么特殊原因吗?还是只是为了演示这个概念?
有更好的例子吗?
就跟你说的一样求和。 如果您学习基础数学,您可能需要计算许多 系列 .
- 1+2+3+...+n
- 1/n+2/n+3/n+...+n/n
- 0+2+3+...+n
- 1^2+2^+3^2+...+n^2
- f(1)+f(2)+f(3)+...+f(n)
- f(1)+f(3)+f(5)+...
我们可以多方面思考。
- 摘要:基本摘要。求和符号我们都在数学课程中学习过。所以不奇怪。
- 修改:在您的第二个版本中,您必须重写所有代码。在第一个版本中不需要。请参阅下面的演示。
- 理解:如果有人看到这样的代码:
(define (1/1+1/2+1/3+...+1/k k) (summation / 1 add1 k))
那么我们只需要将i=1的形式转化为sum of 1/i to i=k(这里是i≤k)就像我们在数学课程中学习它。 - 轻松测试
- extension :也许有一天你想要扩展到向量系列。
如果我们要添加向量系列:vector-1 + vector-2 + ... + vector-n
我们只需要将这个
+
函数(在sum
内)更改为add-vector
并添加if-else
以检查输入是数字还是向量。我们可以设计类似my-inf
这样的东西,这样我们就可以用另一种方式来计算1+2+3+...+inf
. - 新算法或加速:如果我们谈论
sqrt
,我们都同意这种抽象很重要,因为我们有很多算法来计算sqrt
。
#lang racket
(define (sum term a next b)
(if (> a b) 0
(+ (term a) (sum term (next a) next b))))
(define (1+2+...+k k)
(sum identity 1 add1 k))
(define (0^2+1^2+2^2+...+k^2 k)
(sum sqr 0 add1 k))
(define (1+3+5+...+k k)
(sum (λ (n) (- (* 2 n) 1)) 1 add1 k))
(define (1/1+1/2+1/3+...+1/k k)
(sum / 1 add1 k))
(define (1/1^2+1/2^2+1/3^2+...+1/k^2 k)
(sum (λ (n) (/ (sqr n))) 1 add1 k))
; sqr(0)+sqr(2)+sqr(4)+sqr(6)
(sum sqr 0 (λ (a) (+ a 2)) 7) ; 56
;;; TEST
(0^2+1^2+2^2+...+k^2 3) ; 14
(1+2+...+k 100) ; 5050
(1+3+5+...+k 5) ; 1+3+5+7+9=25
(1/1+1/2+1/3+...+1/k 5) ; (+ 1/1 1/2 1/3 1/4 1/5) = 2 + 17/60
(1/1^2+1/2^2+1/3^2+...+1/k^2 3) ; (+ 1 1/4 1/9) = 1 + 13/36
将过程作为参数传递的原因是,通过这种方式您可以参数化您的过程,从而改变它的行为。当然,在原始版本中,您可以简单地将所有数字相加,与第二个版本相同:
(define (sum term a next b)
(if (> a b)
0
(+ (term a) (sum term (next a) next b))))
(define (identity a) a)
(define (plus1 a) (+ 1 a))
(sum identity 1 plus1 10)
=> 55
但现在您也可以灵活地计算其他系列,而无需更改原始代码 - 您只需通过不同的程序即可获得不同的结果。比如,你想计算平方和:
(define (square a) (* a a))
(sum square 1 plus1 10)
=> 385
或者您想计算总和,但跳过数字:
(define (plus2 a) (+ 2 a))
(sum identity 1 plus2 10)
=> 25
这就是高阶程序的强大之处:无需更改基本代码即可定制和扩展。而且由于可以以可组合和可重用的方式编写过程,因此您可以非常灵活地考虑计算,而不必一遍又一遍地编写样板代码。
如果你想计算
f(a0) + f(a0+r) + f(a0+2r) + ...
您不能使用第二个表格,但可以使用 SICP 中的表格。 Scheme 可以帮助您以一种很好的方式实现 ∑.
的抽象概念