Section 1.1.8 introduced the idea that procedures can have internal
definitions, thus leading to a block structure as in the following procedure to
compute square roots:
第 1.1.8 节介绍了过程可以拥有内部定义的思想,由此产生了块结构,如下面这个计算平方根的过程所示:
Now we can use the environment model to see why these internal definitions
behave as desired. Figure 3.11 shows the point in the evaluation of the
expression (sqrt 2) where the internal procedure good-enough? has
been called for the first time with guess equal to 1.
Figure 3.11: Sqrt procedure with internal definitions.
现在,我们可以借助环境模型来理解这些内部定义为何能按预期方式运行。图 3.11 展示了对表达式 (sqrt 2) 求值过程中,内部过程 good-enough? 第一次被调用、此时 guess 等于 1 的那个时刻。图 3.11:带有内部定义的 sqrt 过程。
Observe the structure of the environment. Sqrt is a symbol in the
global environment that is bound to a procedure object whose associated
environment is the global environment. When sqrt was called, a new
environment E1 was formed, subordinate to the global environment, in which the
parameter x is bound to 2. The body of sqrt was then evaluated
in E1. Since the first expression in the body of sqrt is
请观察环境的结构。Sqrt 是全局环境中的一个符号,它被绑定到一个过程对象,该对象所关联的环境正是全局环境。当 sqrt 被调用时,创建了一个新的环境 E1,它从属于全局环境,其中形参 x 被绑定到 2。随后,sqrt 的体在 E1 中被求值。由于 sqrt 体中的第一个表达式是
evaluating this expression defined the procedure good-enough? in the
environment E1. To be more precise, the symbol good-enough? was added
to the first frame of E1, bound to a procedure object whose associated
environment is E1. Similarly, improve and sqrt-iter were defined
as procedures in E1. For conciseness, Figure 3.11 shows only the
procedure object for good-enough?.
对这个表达式的求值,在环境 E1 中定义了过程 good-enough?。更精确地说,符号 good-enough? 被加入 E1 的第一个框架,并被绑定到一个过程对象,该对象所关联的环境是 E1。类似地,improve 和 sqrt-iter 也在 E1 中被定义为过程。为简洁起见,图 3.11 中只展示了 good-enough? 的过程对象。
After the local procedures were defined, the expression (sqrt-iter 1.0)
was evaluated, still in environment E1. So the procedure object bound to
sqrt-iter in E1 was called with 1 as an argument. This created an
environment E2 in which guess, the parameter of sqrt-iter, is
bound to 1. Sqrt-iter in turn called good-enough? with the value
of guess (from E2) as the argument for good-enough?. This set up
another environment, E3, in which guess (the parameter of
good-enough?) is bound to 1. Although sqrt-iter and
good-enough? both have a parameter named guess, these are two
distinct local variables located in different frames. Also, E2 and E3 both
have E1 as their enclosing environment, because the sqrt-iter and
good-enough? procedures both have E1 as their environment part. One
consequence of this is that the symbol x that appears in the body of
good-enough? will reference the binding of x that appears in E1,
namely the value of x with which the original sqrt procedure was
called.
在局部过程被定义之后,表达式 (sqrt-iter 1.0) 仍在环境 E1 中被求值。于是,E1 中绑定到 sqrt-iter 的过程对象以 1 为实参被调用,由此创建了环境 E2,其中 sqrt-iter 的形参 guess 被绑定到 1。sqrt-iter 随后以 E2 中 guess 的值作为实参,调用了 good-enough?。这又建立了另一个环境 E3,其中 good-enough? 的形参 guess 被绑定到 1。尽管 sqrt-iter 和 good-enough? 都有一个名为 guess 的形参,但这是位于不同框架中的两个截然不同的局部变量。此外,E2 和 E3 都以 E1 作为其外围环境,这是因为 sqrt-iter 和 good-enough? 这两个过程的环境部分都是 E1。这一点带来的一个结果是:出现在 good-enough? 体中的符号 x,将引用出现在 E1 中 x 的绑定,即最初调用 sqrt 过程时传入的 x 的值。
The environment model thus explains the two key properties that make local
procedure definitions a useful technique for modularizing programs:
环境模型由此解释了使局部过程定义成为模块化程序的有用技术的两个关键性质:
The names of the local procedures do not interfere with names external to the
enclosing procedure, because the local procedure names will be bound in the
frame that the procedure creates when it is run, rather than being bound in the
global environment.
局部过程的名字不会与外围过程外部的名字相互干扰,因为局部过程的名字被绑定于过程运行时所创建的框架中,而非绑定在全局环境中。
The local procedures can access the arguments of the enclosing procedure,
simply by using parameter names as free variables. This is because the body of
the local procedure is evaluated in an environment that is subordinate to the
evaluation environment for the enclosing procedure.
局部过程可以访问外围过程的实参,只需将形参名作为自由变量使用即可。这是因为局部过程的体是在从属于外围过程求值环境的环境中被求值的。
(define (sqrt x)
(define (good-enough? guess)
( (abs (- (square guess) x)) 0.001))
(define (improve guess)
(average guess (/ x guess)))
(define (sqrt-iter guess)
(if (good-enough? guess)
guess
(sqrt-iter (improve guess))))
(sqrt-iter 1.0)) (define (good-enough? guess)
( (abs (- (square guess) x)) 0.001))