灯下 登录
计算机科学 / SICP / subsection 中英对照

4.1.1 The Core of the Evaluator

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` 作为赋值或定义操作的返回值。

Racket #lang sicp
(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))))
Racket #lang sicp
(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))))
Racket #lang sicp
(define (list-of-values exps env)
 (if (no-operands? exps)
 '()
 (cons (eval (first-operand exps) env)
 (list-of-values
 (rest-operands exps)
 env))))
Racket #lang sicp
(define (eval-if exp env)
 (if (true? (eval (if-predicate exp) env))
 (eval (if-consequent exp) env)
 (eval (if-alternative exp) env)))
Racket #lang sicp
(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))))
Racket #lang sicp
(define (eval-assignment exp env)
 (set-variable-value!
 (assignment-variable exp)
 (eval (assignment-value exp) env)
 env)
 'ok)
Racket #lang sicp
(define (eval-definition exp env)
 (define-variable!
 (definition-variable exp)
 (eval (definition-value exp) env)
 env)
 'ok)