灯下 登录
计算机科学 / SICP / subsection 中英对照

3.5.5 Modularity of Functional Programs and Modularity of Objects

As we saw in 3.1.2, one of the major benefits of introducing

assignment is that we can increase the modularity of our systems by

encapsulating, or “hiding,” parts of the state of a large system within local

variables. Stream models can provide an equivalent modularity without the use

of assignment. As an illustration, we can reimplement the Monte Carlo

estimation of π, which we examined in 3.1.2, from a

stream-processing point of view.

正如我们在 3.1.2 中所见,引入赋值的主要好处之一,是可以通过将大型系统的部分状态封装或"隐藏"在局部变量中,来提高系统的模块性。流模型无需使用赋值,就能提供等价的模块性。以 π 的蒙特卡洛估计为例,我们在 3.1.2 中考察过这一方法,现在从流处理的角度重新实现它。

The key modularity issue was that we wished to hide the internal state of a

random-number generator from programs that used random numbers. We began with

a procedure rand-update, whose successive values furnished our supply of

random numbers, and used this to produce a random-number generator:

关键的模块性问题在于:我们希望对使用随机数的程序隐藏随机数生成器的内部状态。我们从过程 rand-update 出发——其连续的值为我们提供随机数来源——并以此构造一个随机数生成器:

In the stream formulation there is no random-number generator per se,

just a stream of random numbers produced by successive calls to

rand-update:

在流的表述中,不存在独立的随机数生成器,只有一条由对 rand-update 的连续调用所产生的随机数流:

We use this to construct the stream of outcomes of the Cesàro experiment

performed on consecutive pairs in the random-numbers stream:

我们用它来构造对 random-numbers 流中相邻序对执行 Cesàro 实验的结果流:

The cesaro-stream is now fed to a monte-carlo procedure, which

produces a stream of estimates of probabilities. The results are then

converted into a stream of estimates of π. This version of the program

doesn’t need a parameter telling how many trials to perform. Better estimates

of π (from performing more experiments) are obtained by looking farther

into the pi stream:

cesaro-stream 随即被送入 monte-carlo 过程,后者产生一条概率估计流。这些结果再被转换为 π 的估计值流。这个版本的程序不需要一个指定试验次数的参数。要获得更精确的 π 估计(通过进行更多实验),只需向 pi 流中深入查看即可:

There is considerable modularity in this approach, because we still can

formulate a general monte-carlo procedure that can deal with arbitrary

experiments. Yet there is no assignment or local state.

这种方式具有相当好的模块性,因为我们仍然能够构造出一个通用的 monte-carlo 过程来处理任意实验,而其中既没有赋值,也没有局部状态。

Racket #lang sicp
(define rand
 (let ((x random-init))
 (lambda ()
 (set! x (rand-update x))
 x)))
Racket #lang sicp
(define random-numbers
 (cons-stream random-init
 (stream-map rand-update
 random-numbers)))
Racket #lang sicp
(define cesaro-stream
 (map-successive-pairs
 (lambda (r1 r2) (= (gcd r1 r2) 1))
 random-numbers))

(define (map-successive-pairs f s)
 (cons-stream
 (f (stream-car s)
 (stream-car (stream-cdr s)))
 (map-successive-pairs
 f (stream-cdr (stream-cdr s)))))
Racket #lang sicp
(define (monte-carlo experiment-stream
 passed
 failed)
 (define (next passed failed)
 (cons-stream
 (/ passed (+ passed failed))
 (monte-carlo
 (stream-cdr experiment-stream)
 passed
 failed)))
 (if (stream-car experiment-stream)
 (next (+ passed 1) failed)
 (next passed (+ failed 1))))

(define pi
 (stream-map
 (lambda (p) (sqrt (/ 6 p)))
 (monte-carlo cesaro-stream 0 0)))