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 过程来处理任意实验,而其中既没有赋值,也没有局部状态。
(define rand
(let ((x random-init))
(lambda ()
(set! x (rand-update x))
x))) (define random-numbers
(cons-stream random-init
(stream-map rand-update
random-numbers))) (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))))) (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)))