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

2.4 Multiple Representations for Abstract Data

We have introduced data abstraction, a methodology for structuring systems in

such a way that much of a program can be specified independent of the choices

involved in implementing the data objects that the program manipulates. For

example, we saw in 2.1.1 how to separate the task of designing a

program that uses rational numbers from the task of implementing rational

numbers in terms of the computer language’s primitive mechanisms for

constructing compound data. The key idea was to erect an abstraction barrier

– in this case, the selectors and constructors for rational numbers

(make-rat, numer, denom)—that isolates the way rational

numbers are used from their underlying representation in terms of list

structure. A similar abstraction barrier isolates the details of the

procedures that perform rational arithmetic (add-rat, sub-rat,

mul-rat, and div-rat) from the “higher-level” procedures that

use rational numbers. The resulting program has the structure shown in

Figure 2.1.

我们已经介绍了数据抽象——一种构建系统的方法论,使程序的大部分可以独立于程序所操控的数据对象的实现选择加以规定。例如,在 2.1.1 节中,我们看到如何将设计使用有理数的程序这一任务,与用计算机语言的基本构造复合数据的机制来实现有理数的任务分离开来。其关键思想是竖立一道抽象屏障——在这里,即有理数的选择函数和构造函数(`make-rat`、`numer`、`denom`)——将有理数的使用方式与其底层的表结构表示相互隔离。类似的抽象屏障将执行有理数运算的过程(`add-rat`、`sub-rat`、`mul-rat` 和 `div-rat`)的细节,与使用有理数的"更高层"过程隔离开来。所得程序的结构如图 2.1 所示。

These data-abstraction barriers are powerful tools for controlling complexity.

By isolating the underlying representations of data objects, we can divide the

task of designing a large program into smaller tasks that can be performed

separately. But this kind of data abstraction is not yet powerful enough,

because it may not always make sense to speak of “the underlying

representation” for a data object.

这些数据抽象屏障是控制复杂性的有力工具。通过将数据对象的底层表示隔离起来,我们可以将设计大型程序的任务分解为若干可以独立完成的较小任务。但这种数据抽象的能力尚不足够强大,因为有时对一个数据对象而言,谈论"底层表示"并不总是有意义的。

For one thing, there might be more than one useful representation for a data

object, and we might like to design systems that can deal with multiple

representations. To take a simple example, complex numbers may be represented

in two almost equivalent ways: in rectangular form (real and imaginary parts)

and in polar form (magnitude and angle). Sometimes rectangular form is more

appropriate and sometimes polar form is more appropriate. Indeed, it is

perfectly plausible to imagine a system in which complex numbers are

represented in both ways, and in which the procedures for manipulating complex

numbers work with either representation.

一方面,一个数据对象可能存在不止一种有用的表示方式,而我们希望设计能够处理多种表示的系统。举一个简单的例子:复数可以用两种近乎等价的方式表示——直角坐标形式(实部和虚部)和极坐标形式(模和辐角)。有时直角坐标形式更为合适,有时极坐标形式更为合适。事实上,完全可以设想这样一个系统:其中的复数同时以两种形式表示,而操作复数的过程能够与任意一种表示协同工作。

More importantly, programming systems are often designed by many people working

over extended periods of time, subject to requirements that change over time.

In such an environment, it is simply not possible for everyone to agree in

advance on choices of data representation. So in addition to the

data-abstraction barriers that isolate representation from use, we need

abstraction barriers that isolate different design choices from each other and

permit different choices to coexist in a single program. Furthermore, since

large programs are often created by combining pre-existing modules that were

designed in isolation, we need conventions that permit programmers to

incorporate modules into larger systems

additively, that is, without

having to redesign or reimplement these modules.

更重要的是,程序设计系统往往由许多人在漫长的时间跨度内共同设计,并面对随时间变化的需求。在这样的环境中,要求所有人事先就数据表示的选择达成一致,实际上是不可能的。因此,除了将表示与使用隔离开来的数据抽象屏障之外,我们还需要能够将不同设计选择相互隔离、并允许不同选择在同一程序中共存的抽象屏障。此外,由于大型程序往往是通过组合各自独立设计的已有模块来创建的,我们需要一些规约,使程序员能够以可加的 (additively) 方式将模块并入更大的系统,而无需重新设计或重新实现这些模块。

In this section, we will learn how to cope with data that may be represented in

different ways by different parts of a program. This requires constructing

在本节中,我们将学习如何处理程序的不同部分可能以不同方式表示的数据。这需要构造

generic procedures—procedures that can operate on data that may be

represented in more than one way. Our main technique for building generic

procedures will be to work in terms of data objects that have

type tags,

that is, data objects that include explicit information about how they

are to be processed. We will also discuss

data-directed programming,

a powerful and convenient implementation strategy for additively assembling

systems with generic operations.

通用过程 (generic procedures)——能够操作可能以多种方式表示的数据的过程。我们构造通用过程的主要技术是:以带有类型标签 (type tags) 的数据对象来工作,即数据对象中包含关于如何处理它们的显式信息。我们还将讨论数据导向编程 (data-directed programming)——一种强大而便捷的实现策略,用于以可加方式组装具有通用操作的系统。

We begin with the simple complex-number example. We will see how type tags and

data-directed style enable us to design separate rectangular and polar

representations for complex numbers while maintaining the notion of an abstract

“complex-number” data object. We will accomplish this by defining arithmetic

procedures for complex numbers (add-complex, sub-complex,

mul-complex, and div-complex) in terms of generic selectors that

access parts of a complex number independent of how the number is represented.

The resulting complex-number system, as shown in Figure 2.19, contains

two different kinds of abstraction barriers. The “horizontal” abstraction

barriers play the same role as the ones in Figure 2.1. They isolate

“higher-level” operations from “lower-level” representations. In addition,

there is a “vertical” barrier that gives us the ability to separately design

and install alternative representations.

Figure 2.19: Data-abstraction barriers in the complex-number system.

我们从简单的复数例子开始。我们将看到,类型标签与数据导向风格如何使我们能够为复数分别设计直角坐标和极坐标两种表示,同时维护抽象的"复数"数据对象这一概念。为此,我们将用访问复数各部分的通用选择函数来定义复数的算术过程(`add-complex`、`sub-complex`、`mul-complex` 和 `div-complex`),这些选择函数独立于数的具体表示方式。所得的复数系统如图 2.19 所示,包含两种不同类型的抽象屏障。"水平"抽象屏障与图 2.1 中的屏障起着相同的作用,将"较高层"操作与"较低层"表示隔离开来。此外,还有一道"垂直"屏障,使我们能够分别设计和安装各种替代表示。

图 2.19:复数系统中的数据抽象屏障。

In 2.5 we will show how to use type tags and data-directed style

to develop a generic arithmetic package. This provides procedures (add,

mul, and so on) that can be used to manipulate all sorts of “numbers”

and can be easily extended when a new kind of number is needed. In

2.5.3, we’ll show how to use generic arithmetic in a system that performs

symbolic algebra.

在 2.5 节中,我们将展示如何利用类型标签和数据导向风格来开发一个通用算术包。它提供若干过程(`add`、`mul` 等),可用于操作各种各样的"数",并且在需要新的数的类型时易于扩展。在 2.5.3 节中,我们将展示如何在执行符号代数运算的系统中使用通用算术。