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

4.2.1 Normal Order and Applicative Order

In 1.1, where we began our discussion of models of evaluation, we

noted that Scheme is an

applicative-order language, namely, that all

the arguments to Scheme procedures are evaluated when the procedure is applied.

In contrast,

normal-order languages delay evaluation of procedure

arguments until the actual argument values are needed. Delaying evaluation of

procedure arguments until the last possible moment (e.g., until they are

required by a primitive operation) is called

lazy evaluation. Consider the procedure

在第 1.1 节中,我们开始讨论求值模型时曾指出,Scheme 是一种应用序语言 (applicative-order language),即在过程被应用时,其所有实参都会先被求值。与此相对,正则序语言 (normal-order languages) 则将过程实参的求值推迟,直到实际需要该实参的值时才进行。将过程实参的求值推迟到最后一刻(例如,直到某个基本操作需要它时)的做法,称为惰性求值 (lazy evaluation)。考虑下面这个过程

Evaluating (try 0 (/ 1 0)) generates an error in Scheme. With lazy

evaluation, there would be no error. Evaluating the expression would return 1,

because the argument (/ 1 0) would never be evaluated.

在 Scheme 中对 `(try 0 (/ 1 0))` 求值会产生一个错误。而在惰性求值下,这不会引发任何错误。对该表达式求值将返回 1,因为实参 `(/ 1 0)` 永远不会被求值。

An example that exploits lazy evaluation is the definition of a procedure

unless

一个利用惰性求值的例子,是定义一个过程 `unless`

that can be used in expressions such as

它可以用于如下形式的表达式中

This won’t work in an applicative-order language because both the usual value
and the exceptional value will be evaluated before unless is called
(compare Exercise 1.6). An advantage of lazy evaluation is that some
procedures, such as unless, can do useful computation even if evaluation
of some of their arguments would produce errors or would not terminate.

If the body of a procedure is entered before an argument has been evaluated we
say that the procedure is
non-strict in that argument. If the
argument is evaluated before the body of the procedure is entered we say that
the procedure is
strict in that argument. In a purely applicative-order
language, all procedures are strict in each argument. In a purely normal-order
language, all compound procedures are non-strict in each argument, and
primitive procedures may be either strict or non-strict. There are also
languages (see Exercise 4.31) that give programmers detailed control over
the strictness of the procedures they define.

A striking example of a procedure that can usefully be made non-strict is
cons (or, in general, almost any constructor for data structures). One
can do useful computation, combining elements to form data structures and
operating on the resulting data structures, even if the values of the elements
are not known. It makes perfect sense, for instance, to compute the length of
a list without knowing the values of the individual elements in the list. We
will exploit this idea in 4.2.3 to implement the streams of
Chapter 3 as lists formed of non-strict cons pairs.

Racket #lang sicp
(define (try a b)
 (if (= a 0) 1 b))
Racket #lang sicp
(define (unless condition
 usual-value
 exceptional-value)
 (if condition
 exceptional-value
 usual-value))
Racket #lang sicp
(unless (= b 0)
 (/ a b)
 (begin
 (display "exception: returning 0")
 0))