方案: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 可以帮助您以一种很好的方式实现 .

的抽象概念