1.1.5 对于程序性的应用的替代模型

为了执行一个组合,这个组合的操作符是复合的程序,解释器遵循着与组合的操作符是
原生的程序一样的流程。这个流程是在1.1.3部分描述的。也就是,解释器执行组合
的元素,然后应用 程序(组合的操作符的值)和实际参数(组合的操作数的值)。

我们假定应用原生的程序与实际参数的机制被嵌入了解释器。对于复合程序,应用流程如下:

为了应用复合的程序和实际参数,执行带形式参数的程序的程序体,形式参数用实际的
参数替换。

为了演示这个流程,让我们执行组合:
(f 5)

f是在1.1.4部分中被定义的程序。我们开始检索到f的程序体
(sum-of-squares (+ a 1) (* a 2))
然后我们用实际的参数5来替换形式参数a.
(sum-of-squares (+ 5 1) (* 5 2))
因此,问题归结为 对有两个操作数和一个操作符sum-of-squares的组合,进行执行。
执行这个组合包括三个子问题。我们必须执行被应用到程序的操作符,并且
我们必须执行得到实参的操作数。现在,(+ 5 1)生成6和 (* 5 2)生成 10,
所以我们必须应用程序 sum-of-squares 和实际参数 6,10.  这些值被替换到
sum-of-squares的程序体的形式参数中。归结为如下的表达式:
(+ (square 6) (square 10))
如果我们使用square的定义,这将归结为
(+ (* 6 6)(* 10 10))
接着被乘法归结为
(+ 36 100)
于是最终的结果为
136
 我们刚刚描述的这个流程被叫做应用程序的替换模型。
 它作为一个确定应用程序含义的模型。仅限于本章中关注的程序。
 然后,有两点应该注意:

1替换的目的是帮助我们思考应用程序,不是提供解释器如何实际工作的描述。
经典的解释器没有执行应用程序通过替换形式参数的值的方式。在实践中,
为了形式参数,是使用本地的环境变量来完成替换的。我们将在第三章与第四章中
详细地讨论这些细节。

2随着本书的课程,我们将展示一系列的关于解释器如何工作的日益详尽的模型,
最终以第五章中的解释器和编译器的一个完整的实现来结尾。替换模型仅是这些模型中
的第一个,是关于执行流程的形式化的思维的开始的一种方式。总之,在科学与工程中,
当对现象进行模型化时,我们开始于一个简单的,不完善的模型。在我们对更多的细节
进行考虑时,这些简化的模型看起来是不足的,必须被更好的模型替换掉。
替换模型也不例外。在特别的,当我们在第三章中使用有交互操作的程序时,
我们将看到替换模型失灵了,必须被替换成一个更加复杂的应用程序模型。

* 应用序与自然序
根据1.1.3部分中的执行的描述,解释器首先执行操作符和操作数,然后应用于目标的
程序与目标的实际参数。 这并不是执行解释操作的唯一方式。另一个执行模型
并不执行操作数,直到需要时才执行。代替首先替换操作数表达式中的参数,而是
直到表达式仅包括原生的操作符时,才执行解释。如果我们使用这种方法,如下的表达式的执行:

(f 5)

将展开为如下的序列:

(sum-of-squares (+ 5 1) (* 5 2)
(+ (square (+ 5 1)) (square (* 5 2)) )
(+  (* (+ 5 1) (+ 5 1)) (* (* 5 2) (* 5 2)) )

接下来的计算如下:

(+  (* 6 6) (* 10 10))
(+ 36 100)
136

这正如之前的执行模型一样,得到了相同的答案,但是流程却不同了。
特别是 (+ 5 1) 和 (* 5 2)都执行了两次,对应于(* X X)表达式的归约。
这种先完全展开再进行归约的执行方法被称为自然序。相反的是解释器实际使用的
先执行实际参数再应用的方法,被叫做应用序。这里展示的是,对于使用替换模型的
应用程序(包括本书前两章的所有的程序),输入合法的数值,自然序与应用序
都执行得到相同的结果。(看练习1.5,对于一个非法的数值的例子,自然序与应用序
的执行没有得到相同的结果值)

LISP使用应用序的执行,部分因为从避免表达式的多次执行(例如 上述 (+ 5 1)
和 (* 5 2)的展示)获得附加的效率,更重要的是因为,当离开能够被替换模型
模型化的程序的领域后,自然序的执行将变得更加复杂。另一方面,自然序能够成为
一个极有用的工具,我们将在第三章和第四章中研究它的应用。

猜你喜欢

转载自blog.csdn.net/gggwfn1982/article/details/81384641