The evaluation process can be described as the interplay between two
procedures: eval and apply.
Subheading: Eval
求值过程可以描述为两个过程之间的相互作用:`eval` 与 `apply`。小节标题:Eval
Eval takes as arguments an expression and an environment. It classifies
the expression and directs its evaluation. Eval is structured as a case
analysis of the syntactic type of the expression to be evaluated. In order to
keep the procedure general, we express the determination of the type of an
expression abstractly, making no commitment to any particular representation
for the various types of expressions. Each type of expression has a predicate
that tests for it and an abstract means for selecting its parts. This
`eval` 以一个表达式和一个环境为参数,对表达式进行分类并指导其求值。`eval` 的结构是对待求值表达式的语法类型进行情况分析。为使该过程具有通用性,我们抽象地确定表达式的类型,不对各类表达式的具体表示做任何承诺。每种类型的表达式都有一个用于检测该类型的谓词,以及一种用于选取其各组成部分的抽象手段。这种
abstract syntax makes it easy to see how we can change the syntax of
the language by using the same evaluator, but with a different collection of
syntax procedures.
Primitive expressions
抽象语法 (abstract syntax) 使我们可以清楚地看到:只需使用同一个求值器,但配以不同的语法过程集合,就能改变语言的语法。基本表达式
For self-evaluating expressions, such as numbers, eval returns the
expression itself.
对于自求值表达式(如数),`eval` 直接返回该表达式本身。
Eval must look up variables in the environment to find their values.
Special forms
`eval` 必须在环境中查找变量以求得其值。特殊形式
For quoted expressions, eval returns the expression that was quoted.
对于被引用的表达式,`eval` 返回被引用的那个表达式。
An assignment to (or a definition of) a variable must recursively call
eval to compute the new value to be associated with the variable. The
environment must be modified to change (or create) the binding of the variable.
对变量的赋值(或定义)必须递归调用 `eval` 以计算与该变量关联的新值,并修改环境以改变(或创建)该变量的绑定。
An if expression requires special processing of its parts, so as to
evaluate the consequent if the predicate is true, and otherwise to evaluate the
alternative.
`if` 表达式需要对其各组成部分进行特殊处理:若谓词为真,则求值后件;否则求值替代项。
A lambda expression must be transformed into an applicable procedure by
packaging together the parameters and body specified by the lambda
expression with the environment of the evaluation.
`lambda` 表达式必须通过将 `lambda` 表达式所指定的形参与体,连同求值时的环境一起打包,转换为一个可应用的过程。
A begin expression requires evaluating its sequence of expressions in
the order in which they appear.
`begin` 表达式要求按各表达式的出现顺序依次对其求值。
A case analysis (cond) is transformed into a nest of if
expressions and then evaluated.
Combinations
情况分析(`cond`)被转换为嵌套的 `if` 表达式,然后再求值。组合式
For a procedure application, eval must recursively evaluate the operator
part and the operands of the combination. The resulting procedure and
arguments are passed to apply, which handles the actual procedure
application.
Here is the definition of eval:
对于过程应用,`eval` 必须递归地对组合式的运算符部分和各运算对象求值,然后将所得的过程和实参传递给 `apply`,由它来处理实际的过程应用。以下是 `eval` 的定义:
For clarity, eval has been implemented as a case analysis using
cond. The disadvantage of this is that our procedure handles only a few
distinguishable types of expressions, and no new ones can be defined without
editing the definition of eval. In most Lisp implementations,
dispatching on the type of an expression is done in a data-directed style.
This allows a user to add new types of expressions that eval can
distinguish, without modifying the definition of eval itself. (See
Exercise 4.3.)
Subheading: Apply
为清晰起见,`eval` 用 `cond` 实现为情况分析。其缺点在于:我们的过程只能处理为数不多的几种可区分的表达式类型,若不修改 `eval` 的定义就无法添加新类型。在大多数 Lisp 实现中,对表达式类型的分派采用数据导向 (data-directed) 的风格来完成。这允许用户添加新的表达式类型,使 `eval` 能够识别它们,而无需修改 `eval` 的定义本身。(见练习 4.3。)小节标题:Apply
Apply takes two arguments, a procedure and a list of arguments to which
the procedure should be applied. Apply classifies procedures into two
kinds: It calls apply-primitive-procedure to apply primitives; it
applies compound procedures by sequentially evaluating the expressions that
make up the body of the procedure. The environment for the evaluation of the
body of a compound procedure is constructed by extending the base environment
carried by the procedure to include a frame that binds the parameters of the
procedure to the arguments to which the procedure is to be applied. Here is
the definition of apply:
`apply` 接受两个参数:一个过程,以及该过程将被应用的实参表。`apply` 将过程分为两类:对于基本过程,它调用 `apply-primitive-procedure` 来应用;对于复合过程,它通过依次求值构成过程体的各表达式来加以应用。求值复合过程体时所在的环境,是通过将过程所携带的基础环境加以扩展而构造的——扩展方式是添加一个框架,将过程的形参绑定到该过程被应用的实参上。以下是 `apply` 的定义:
Subheading: Procedure arguments
小节标题:过程的实参
When eval processes a procedure application, it uses
list-of-values to produce the list of arguments to which the procedure
is to be applied. List-of-values takes as an argument the operands of
the combination. It evaluates each operand and returns a list of the
corresponding values:
当 `eval` 处理过程应用时,它使用 `list-of-values` 生成该过程将被应用的实参表。`list-of-values` 以组合式的运算对象为参数,对每个运算对象求值,并返回由相应值组成的表:
Subheading: Conditionals
小节标题:条件式
Eval-if evaluates the predicate part of an if expression in the
given environment. If the result is true, eval-if evaluates the
consequent, otherwise it evaluates the alternative:
`eval-if` 在给定环境中对 `if` 表达式的谓词部分求值。若结果为真,`eval-if` 对后件求值;否则对替代项求值:
The use of true? in eval-if highlights the issue of the
connection between an implemented language and an implementation language. The
if-predicate is evaluated in the language being implemented and thus
yields a value in that language. The interpreter predicate true?
translates that value into a value that can be tested by the if in the
implementation language: The metacircular representation of truth might not be
the same as that of the underlying Scheme.
Subheading: Sequences
在 `eval-if` 中使用 `true?` 凸显了被实现语言与实现语言之间的连接问题。`if` 的谓词在被实现的语言中求值,因而产生的是该语言中的一个值。解释器谓词 `true?` 将该值转换为可供实现语言中的 `if` 检验的值:元循环对真值的表示未必与底层 Scheme 的表示相同。小节标题:序列
Eval-sequence is used by apply to evaluate the sequence of
expressions in a procedure body and by eval to evaluate the sequence of
expressions in a begin expression. It takes as arguments a sequence of
expressions and an environment, and evaluates the expressions in the order in
which they occur. The value returned is the value of the final expression.
`eval-sequence` 由 `apply` 用于对过程体中的表达式序列依次求值,也由 `eval` 用于对 `begin` 表达式中的表达式序列依次求值。它接受一个表达式序列和一个环境作为参数,按表达式在序列中出现的顺序逐一求值,最终返回最后一个表达式的值。
Subheading: Assignments and definitions
小节:赋值与定义
The following procedure handles assignments to variables. It calls eval
to find the value to be assigned and transmits the variable and the resulting
value to set-variable-value! to be installed in the designated
environment.
下面的过程负责处理对变量的赋值。它调用 `eval` 求出待赋的值,再将变量和所得的值传给 `set-variable-value!`,使其安装到指定的环境中。
Definitions of variables are handled in a similar manner.
变量的定义以类似的方式处理。
We have chosen here to return the symbol ok as the value of an
assignment or a definition.
这里我们选择将符号 `ok` 作为赋值或定义操作的返回值。
(define (eval exp env)
(cond ((self-evaluating? exp)
exp)
((variable? exp)
(lookup-variable-value exp env))
((quoted? exp)
(text-of-quotation exp))
((assignment? exp)
(eval-assignment exp env))
((definition? exp)
(eval-definition exp env))
((if? exp)
(eval-if exp env))
((lambda? exp)
(make-procedure
(lambda-parameters exp)
(lambda-body exp)
env))
((begin? exp)
(eval-sequence
(begin-actions exp)
env))
((cond? exp)
(eval (cond->if exp) env))
((application? exp)
(apply (eval (operator exp) env)
(list-of-values
(operands exp)
env)))
(else
(error "Unknown expression
type: EVAL" exp)))) (define (apply procedure arguments)
(cond ((primitive-procedure? procedure)
(apply-primitive-procedure
procedure
arguments))
((compound-procedure? procedure)
(eval-sequence
(procedure-body procedure)
(extend-environment
(procedure-parameters
procedure)
arguments
(procedure-environment
procedure))))
(else
(error "Unknown procedure
type: APPLY"
procedure)))) (define (list-of-values exps env)
(if (no-operands? exps)
'()
(cons (eval (first-operand exps) env)
(list-of-values
(rest-operands exps)
env)))) (define (eval-if exp env)
(if (true? (eval (if-predicate exp) env))
(eval (if-consequent exp) env)
(eval (if-alternative exp) env))) (define (eval-sequence exps env)
(cond ((last-exp? exps)
(eval (first-exp exps) env))
(else
(eval (first-exp exps) env)
(eval-sequence (rest-exps exps)
env)))) (define (eval-assignment exp env)
(set-variable-value!
(assignment-variable exp)
(eval (assignment-value exp) env)
env)
'ok) (define (eval-definition exp env)
(define-variable!
(definition-variable exp)
(eval (definition-value exp) env)
env)
'ok)