3.2.2 应用简单的程序
当我们介绍1.1.5部分中的替换模型时,我们显示了如何把组合表达式
(f 5)解释成136,给出了如下的程序定义:

(define (square x) (* x x)
(define (sum-of-squares x y)
       (+ (square x) (square y))
)
(define (f a)
       (sum-of-squares (+ a 1) (* a 2))
)

我们使用环境模型分析相同的例子.图3.4显示了通过解释全局环境中
的f,square,sum-of-squares的定义,创建了三个程序对象.任何一个程序
对象都包括了一些代码,和一个指向全局环境的指针.

 

3.2.2 应用简单的程序

 图3.4 在全局帧中的程序对象

 

在图3.5中,我们看到了通过解释表达式(f 5)来创建环境结构。
f的调用创建了一个新的环境 “环境1”,开始了一个帧,a在帧中。
它是f的形式参数。绑定实际参数5。在环境1中,我们解释f的程序体:

(sum-of-squares (+ a 1) (* a 2))

 

3.2.2 应用简单的程序

 

图3.5 使用在图3.4中的程序来解释(f 5)创建的环境

 

为了解释这个组合的表达式,我们首先解释它的子表达式。第一个子表达式,
sum-of-squares,有一个值是一个程序对象。(注意这个值是如何发现的:
我们首先在环境1的第一个帧中找,没有包括sum-of-squares的绑定。然后,
我们继续找它的父环境,即全局环境,找到了它的绑定,如图3.4的显示)
其它的两个子表达式是通过应用原生的操作+和*来解释两个组合的表达式
(+  a 1)和(* a 2)相应地得到了6和10,而解释的。

现在我们应用程序对象sum-of-squares到实际参数6和10。
在一个新的环境“环境2”中的结果是形式参数x,y被绑定到实际参数.
在环境2中我们解释组合表达式(+ (square x) (square y)).这导致我们解释
(square x),square被发现在全局帧中,x是6。一旦,重复,我们安装了
一个新的环境“环境3”,在其中x被绑定为6,在这个环境中,我们解释square的
程序体即(* x x).也作为应用sum-of-squares的一部分,我们必须解释子表达式
(square y),并且y等于10。对square的第二次调用,创建了一个新的环境,“环境4”
在这个环境中,x是square的形式参数,它被绑定为10。在环境4中我们必须
解释的是(* x x)。

注意的重要的点是对square的任何一次调用都创建一个新的环境包括一个对x的绑定。
我们这里能看到不同的帧如何保持独立的不同的局部变量,尽管它们的名称都是x.
注意的是square创建的任何一帧都指向全局环境,因为这是square程序对象所指向的
环境。

子表达式被解释后,结果就返回了。对square的两个调用生成的值,在sum-of-squares
程序中被相加,这个结果由f返回。因为我们这里的聚焦于环境的结构,我们没有关注到
这些返回值如何从一个调用传递到另一个调用.然而这也是解释的执行过程中
的另一个重要的方面,我们将在第五章中讨论它的细节之处。

练习3.9
在1.2.1部分中,我们使用替换模型来分析计算斐波那些数的两个程序,一个是递归版本。

(define (factorial n)
   (if (= n 1)
     1
     (* n (factorial (- n 1) ) )
   )
)
一个是迭代版本。
(define (factorial n)
   (fact-iter 1 1 n))

(define (fact-iter product counter max-count)
     (if (> counter max-count)
        product
 (fact-iter (* counter product)
            (+ counter 1)
     max-count)
     )
)

显示由解释(factorial 6)创建的环境的结构,使用斐波那些数的程序
的任何一个版本。

相关文章: