3.2.1 评估的规则
解释器如何评估一个组合的表达式的整体性的规范,与我们在1.1.3部分中开始介绍的内容是一致的。
为了评估表达式:
1。评估表达式的子表达式
2。应用操作符子表达式的值到操作数子表达式的值。
评估的环境模型,代替了替换模型,用来指定,应用一个复合程序到参数的含义。
在评估的环境模型中,一个程序总是一个数对,包括了一些代码和一个指向环境的指针。
程序被创建仅有一种方式。即通过评估一个lambda 表达式。这产生的程序,这个程序的代码来自于lambda表达式的文本,
它的环境是lambda表达式被评估的以产生程序的环境。例如,考虑如下的程序定义。
(define (square x)
(* x x))
上述定义,被评估在全局的环境中。程序定义的语法是仅仅是一个隐藏的lambda表达式的语法糖。
它是如下的表达式的等价形式。
(define square
(lambda (x) (* x x )))
上述的表达式在评估(lambda (x) (* x x ))时,绑定square到全局环境中的结果值。
图3.2显示出了这种define表达式的评估的结果。程序对象是一个数对,代码部分是
一个程序,有一个形式参数,命名为x,和一个程序体(* x x).
这个程序的环境部分是一个指针指到全局环境。因为那是 lambda表达式被评估的环境。
一个新的绑定,也就是把符号square和程序对象关联起来,再加入到全局的帧中。
总之,define 创建的定义通过添加绑定到帧中。
global env ----> |------------------|
| other variable |
| squares: - |
|---------- |------|
(define (square x) | ^
(* x x )) | |
! |
(*)(*)-
|
|
!
parameters : x
body: (* x x)
图3.2 在全局的环境中,通过评估(define (square x) (* x x))产生的环境结构
现在我们看到了程序如何创建。我们能描述程序如何被应用。环境模型指定,为了应用程序到参数,
创建一个新的环境包括了一个帧,这个帧把形式参数绑定到实际参数的值。这个帧的外部环境
是被程序指定的环境。现在,这个新环境,评估程序体。
为了显示这个规则如何被遵循,图3.3展示了环境结构是如何创建的。通过评估
表达式(square 5),在全局环境中。square是图3.2中程序生成的。
在一个新的环境的创建中应用一个程序的结果,在图中标签为E1,开始一个帧x,程序的形式参数,
被绑定为5。这个帧的指针指向全局环境。全局环境在此终止,因为这个环境显示了square程序的部分。
有E1,我们能评估程序的程序体,(* X X). 因为在E1中,x的值是5,结果是(* 5 5)或者是25。
global env ----> |------------------------------|
| other variable |
| squares: - |
|---------- |------------------|
(square 5) | ^ ^
| | |
! | |
(*)(*)- |
| _____|_____
| E1---->| x:5 |
! |_________|
parameters : x
body: (* x x)
图3.3 在全局环境中,评估(square 5)时创建的环境
程序的环境模型能被总结为两条规则:
1.通过组装一个帧,把程序的形式参数绑定到调用的实际参数上,一个程序对象能被
应用到一组实际参数的集合上,然后在新组装的环境的上下文内解释程序体.新的帧
有它自已的父环境,即程序对象被应用的环境部分.
2.以解释lambda表达式的方式创建的程序与一个给定的环境相关联.得到的程序对象是
一个数对,它由lambda表达式的文本和指向程序被创建的环境的指针组成.
我们也指定了定义一个符号使用define在当前的环境帧创建一个绑定
并且给符号赋值所示的值.最后,我们指定set!的行为,这个操作
是第一处强迫我们介绍环境模型的.解释表达式(set! <variable> <value>)在某个环境定位环境中的变量绑定,
并且改变绑定来指示出新的值.也就是说,在环境
的第一个帧中发现了包括了变量的一个绑定,修改那个帧.
如果变量在环境中没有绑定,set!报一个错误.
这些解释规则,尽管被认为比替换模型更复杂,它仍然是很合理很自然的.
进则,解释模型,尽管抽象,提供了一个为解释器如何解释表达式的正确的描述.
在第四章中,我们将看到这个模型如何能作为实现一个可工作的解释器的蓝图.
如下的部分,通过分析一些示例性的程序,描述了这个模型的细节.