翻译连载 第6篇 计算机编程的编程结构与解释

1.1.3 评估组合子
在这一章中我们的目标是独立出关于程序性的思维的问题。
作为一个点的案例,让我们考虑下,在组合的执行中,解释器本身
遵循的程序。

为了执行一个组合,操作如下:
1. 执行组合的子表达式
2. 应用 最左子表达式(操作符)的值作为程序名以及它的
其它的子表达式(操作数)的值作为实际参数。

总之,这个简单的规则展示出关于流程的一些重要的观点。
首先,为了完成组合的执行流程,第一步要求是我们必须首先
执行组合的任何一个元素的执行流程。因此,执行规则在本质上是递归的;
也就是,它的步骤之一,需要调用规则本身。

注意到递归的思想能够被多么简洁地用来表达什么,在深度嵌套的组合的例子中,
否则将被视作一个相当复杂的流程。例如,执行如下的表达式:
(* (+ 2 (* 4 6))
    (+ 3 5 7))
要求执行规则被应用于四个不同的组合。通过用树形的形式表示组合,我们
能够得到这个流程的图画,如1.1所示。任何一个组合被表示成带有分支的结点,
分支对应着组合的操作符与操作数。叶子结点表示操作符或者数字。用语法树来看待
执行,我们能够想象到操作数的值的上溯过程,从叶子结点开始,然后合成越来越高的
层级。总之,我们看到递归是一项处理层级,即像树一样的对象的强有力的技术。
事实上,执行规则的上溯数值是一种通用的流程(树递归)的一个例子。

                390
                  |
V-----<------V--------->-----V
*               26              15
                 |                   |
         V-<-V--V        V---V---V--V
         +     2  24       +   3   5  7
                     |
            V--V-V
              *  4 6
图1.1显示着任何一个子组合的值的树形递归

接下来,值得注意的是第一步的重复应用带给我们的要点是哪需要执行,
不是组合,而是例如数字,内嵌的操作符或者是其它的名称等原生的表达式。
我们注意到原生的情况规定如下:

数字的值是它的本身。
内嵌操作符的值是机器指令序列执行相应的操作的结果。
其它的名称的值是这些名字在环境变量中相关联的对象。

通过规定符号例如+和*也包含在全局环境变量中并且关联到
机器指令的序列,我们可以把第二条规则视为第三条规则的一个特例。
注意到的关键点是环境的角色是确定符号在环境变量中的含义。
在一个交互的语言中,例如LISP,说出一个表达式的值例如X+1,却没有指出环境变量
的任何信息,例如符号X的含义 是没有实际意义的。 正如我们在第三章中看到的那样,
对于环境变量的通常的观念是提供了在程序执行时的上下文,在我们对程序的
执行的理解中,起到非常重要的作用。

注意到执行规则没有提到如何处理定义。例如执行(define x 3)并不是应用define
用两个实际参数,一个是X的值,一个是3.因为define的目的是准确地把X与一个值
关联起来。也就是说,(define x 3)不是一个组合。

对于通用的执行规则的这个例外,被称为特定的定义符。define是我们目前为止
看到的特定的定义符中的仅有的例子,但是很快我们能看到其它的例子。任何一个
特定的定义符都有它自己的执行规则。表达式(任何一个都有自己的执行规则)的多样性
组成了编程语言的语法。在与其它的大部分的编程语言比较中,LISP有很简单的一套语法。
也就是表达式的执行规则能够被描述成一个简单的通用规则加上一些特定的定义符的特定
规则。

猜你喜欢

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