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

2.1.3 What Is Meant by Data?

We began the rational-number implementation in 2.1.1 by

implementing the rational-number operations add-rat, sub-rat, and

so on in terms of three unspecified procedures: make-rat, numer,

and denom. At that point, we could think of the operations as being

defined in terms of data objects—numerators, denominators, and rational

numbers—whose behavior was specified by the latter three procedures.

我们在 2.1.1 节中开始实现有理数时,先用三个未加说明的过程 make-rat、numer 和 denom 定义了有理数运算 add-rat、sub-rat 等。在那个阶段,我们可以认为这些运算是在数据对象——分子、分母和有理数——的基础上定义的,而这些数据对象的行为由后三个过程来描述。

But exactly what is meant by

data? It is not enough to say

“whatever is implemented by the given selectors and constructors.” Clearly,

not every arbitrary set of three procedures can serve as an appropriate basis

for the rational-number implementation. We need to guarantee that, if we

construct a rational number x from a pair of integers n and

d, then extracting the numer and the denom of x and

dividing them should yield the same result as dividing n by d.

In other words, make-rat, numer, and denom must satisfy

the condition that, for any integer n and any non-zero integer d,

if x is (make-rat n d), then

(numer x)

(denom x)

但"数据 (data)"究竟意味着什么?仅仅说"由给定选择函数和构造函数所实现的东西"是不够的。显然,并非任意三个过程的组合都能作为有理数实现的合适基础。我们需要保证:如果用一对整数 n 和 d 构造了一个有理数 x,那么取出 x 的 numer 和 denom 再相除,应当与 n 除以 d 得到相同的结果。换言之,make-rat、numer 和 denom 必须满足如下条件:对任意整数 n 和任意非零整数 d,若 x 是 (make-rat n d),则

(numer x)

(denom x)

=

n
d

.

In fact, this is the only condition make-rat, numer, and

denom must fulfill in order to form a suitable basis for a

rational-number representation. In general, we can think of data as defined by

some collection of selectors and constructors, together with specified

conditions that these procedures must fulfill in order to be a valid

representation.

事实上,这是 make-rat、numer 和 denom 为构成有理数表示的合适基础所必须满足的唯一条件。一般地,我们可以把数据理解为由若干选择函数和构造函数以及这些过程必须满足的特定条件共同定义的东西,只有满足这些条件,这些过程才构成有效的表示。

This point of view can serve to define not only “high-level” data objects,

such as rational numbers, but lower-level objects as well. Consider the notion

of a pair, which we used in order to define our rational numbers. We never

actually said what a pair was, only that the language supplied procedures

cons, car, and cdr for operating on pairs. But the only

thing we need to know about these three operations is that if we glue two

objects together using cons we can retrieve the objects using car

and cdr. That is, the operations satisfy the condition that, for any

objects x and y, if z is (cons x y) then (car

z) is x and (cdr z) is y. Indeed, we mentioned that

these three procedures are included as primitives in our language. However,

any triple of procedures that satisfies the above condition can be used as the

basis for implementing pairs. This point is illustrated strikingly by the fact

that we could implement cons, car, and cdr without using

any data structures at all but only using procedures. Here are the

definitions:

这种观点不仅可以用来定义"高层"数据对象(如有理数),也可以用来定义更低层的对象。考虑序对的概念——我们用它来定义有理数。我们从未真正说明序对是什么,只是说语言提供了操作序对的过程 cons、car 和 cdr。但关于这三个操作,我们唯一需要知道的是:如果用 cons 把两个对象粘合在一起,就能用 car 和 cdr 分别取回这两个对象。也就是说,这些操作满足如下条件:对任意对象 x 和 y,若 z 是 (cons x y),则 (car z) 是 x,(cdr z) 是 y。我们曾提到,这三个过程在我们的语言中作为基本过程而存在。然而,任何满足上述条件的三个过程都可以作为实现序对的基础。这一点通过如下事实得到了有力说明:我们完全可以不借助任何数据结构,仅用过程来实现 cons、car 和 cdr。其定义如下:

This use of procedures corresponds to nothing like our intuitive notion of what

data should be. Nevertheless, all we need to do to show that this is a valid

way to represent pairs is to verify that these procedures satisfy the condition

given above.

这种用过程来表示数据的方式与我们对数据的直觉认识相去甚远。尽管如此,要证明这是表示序对的有效方式,我们所需做的只是验证这些过程满足上面给出的条件。

The subtle point to notice is that the value returned by (cons x y) is a

procedure—namely the internally defined procedure dispatch, which

takes one argument and returns either x or y depending on whether

the argument is 0 or 1. Correspondingly, (car z) is defined to apply

z to 0. Hence, if z is the procedure formed by (cons x

y), then z applied to 0 will yield x. Thus, we have shown that

(car (cons x y)) yields x, as desired. Similarly, (cdr

(cons x y)) applies the procedure returned by (cons x y) to 1, which

returns y. Therefore, this procedural implementation of pairs is a

valid implementation, and if we access pairs using only cons,

car, and cdr we cannot distinguish this implementation from one

that uses “real” data structures.

值得注意的微妙之处在于:(cons x y) 返回的值是一个过程——即内部定义的过程 dispatch,它接受一个参数,根据参数是 0 还是 1 分别返回 x 或 y。相应地,(car z) 被定义为将 z 应用于 0。因此,若 z 是由 (cons x y) 产生的过程,则 z 应用于 0 将得到 x。由此我们证明了 (car (cons x y)) 确实得到 x,正如所期望的。类似地,(cdr (cons x y)) 将 (cons x y) 返回的过程应用于 1,得到 y。因此,序对的这种过程式实现是有效的,而且如果我们只通过 cons、car 和 cdr 来访问序对,就无法将这种实现与使用"真实"数据结构的实现区分开来。

The point of exhibiting the procedural representation of pairs is not that our

language works this way (Scheme, and Lisp systems in general, implement pairs

directly, for efficiency reasons) but that it could work this way. The

procedural representation, although obscure, is a perfectly adequate way to

represent pairs, since it fulfills the only conditions that pairs need to

fulfill. This example also demonstrates that the ability to manipulate

procedures as objects automatically provides the ability to represent compound

data. This may seem a curiosity now, but procedural representations of data

will play a central role in our programming repertoire. This style of

programming is often called

message passing, and we will be using it

as a basic tool in Chapter 3 when we address the issues of modeling and

simulation.

展示序对的过程式表示,其意义并不在于说明我们的语言确实是这样工作的(Scheme 以及一般的 Lisp 系统出于效率原因会直接实现序对),而在于说明它可以这样工作。过程式表示虽然晦涩,却是表示序对的完全充分的方式,因为它满足了序对所需满足的唯一条件。这个例子还表明,将过程作为对象加以操纵的能力,自然地提供了表示复合数据的能力。这看起来目前不过是个小花絮,但数据的过程式表示将在我们的程序设计知识库中扮演核心角色。这种程序设计风格常被称为消息传递 (message passing),在第 3 章讨论建模与模拟问题时,我们将把它作为基本工具来使用。

Racket #lang sicp
(define (cons x y)
 (define (dispatch m)
 (cond ((= m 0) x)
 ((= m 1) y)
 (else
 (error "Argument not 0 or 1:
 CONS" m))))
 dispatch)

(define (car z) (z 0))
(define (cdr z) (z 1))