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

2.2.4 Example: A Picture Language

This section presents a simple language for drawing pictures that illustrates

the power of data abstraction and closure, and also exploits higher-order

procedures in an essential way. The language is designed to make it easy to

experiment with patterns such as the ones in Figure 2.9, which are

composed of repeated elements that are shifted and scaled. In this language, the data

objects being combined are represented as procedures rather than as list

structure. Just as cons, which satisfies the closure property, allowed

us to easily build arbitrarily complicated list structure, the operations in

this language, which also satisfy the closure property, allow us to easily

build arbitrarily complicated patterns.

Figure 2.9: Designs generated with the picture language.

Subheading: The picture language

本节介绍一种用于绘图的简单语言,以此阐明数据抽象 (data abstraction) 与闭包性质的威力,并以本质性的方式运用了高阶过程 (higher-order procedures)。这门语言的设计目标是便于试验如图 2.9 所示的各种图案——这些图案由反复移位、缩放的元素组合而成。在该语言中,被组合的数据对象以过程而非表结构的形式表示。正如满足闭包性质的 cons 使我们得以轻松构造任意复杂的表结构,这门语言中同样满足闭包性质的各种操作,也使我们得以轻松构造任意复杂的图案。

图 2.9:用图像语言生成的图案设计。

小节标题:图像语言

When we began our study of programming in 1.1, we emphasized the

importance of describing a language by focusing on the language’s primitives,

its means of combination, and its means of abstraction. We’ll follow that

framework here.

在 1.1 节开始研究程序设计时,我们强调了描述一门语言应关注三个要素:语言的基本表达式 (primitives)、组合的方法 (means of combination) 以及抽象的方法 (means of abstraction)。我们在此也将沿用这一框架。

Part of the elegance of this picture language is that there is only one kind of

element, called a

painter. A painter draws an image that is shifted

and scaled to fit within a designated parallelogram-shaped frame. For example,

there’s a primitive painter we’ll call wave that makes a crude line

drawing, as shown in Figure 2.10. The actual shape of the drawing

depends on the frame—all four images in figure 2.10 are produced by the

same wave painter, but with respect to four different frames. Painters

can be more elaborate than this: The primitive painter called rogers

paints a picture of MIT’s founder, William Barton Rogers, as shown in

Figure 2.11. The four images in figure 2.11 are drawn with respect to the same four

frames as the wave images in figure 2.10.

这门图像语言的优雅之处在于,它只有一种元素,称为画家 (painter)。一个画家能绘制一幅图像,该图像经移位和缩放后恰好填满指定的平行四边形形状的框架 (frame)。例如,有一个基本画家 (primitive painter) 我们称之为 wave,它绘制一幅粗糙的线条画,如图 2.10 所示。具体的图形形状取决于所用的框架——图 2.10 中的四幅图像均由同一个 wave 画家绘制,但分别对应四个不同的框架。画家可以比这更为精细:名为 rogers 的基本画家绘制的是 MIT 创始人威廉·巴顿·罗杰斯 (William Barton Rogers) 的肖像,如图 2.11 所示。图 2.11 中的四幅图像是以与图 2.10 中 wave 图像相同的四个框架为基础绘制的。

Figure 2.10: Images produced by the wave painter, with respect to four different frames. The frames, shown with dotted lines, are not part of the images.

图 2.10:wave 画家相对于四个不同框架所生成的图像。框架以虚线表示,不属于图像的组成部分。

Figure 2.11: Images of William Barton Rogers, founder and first president of MIT, painted with respect to the same four frames as in Figure 2.10 (original image from Wikimedia Commons).

图 2.11:MIT 创始人兼首任校长威廉·巴顿·罗杰斯的肖像,以与图 2.10 相同的四个框架为基础绘制(原图来自维基共享资源)。

To combine images, we use various operations that construct new painters from

given painters. For example, the beside operation takes two painters

and produces a new, compound painter that draws the first painter’s image in

the left half of the frame and the second painter’s image in the right half of

the frame. Similarly, below takes two painters and produces a compound

painter that draws the first painter’s image below the second painter’s image.

Some operations transform a single painter to produce a new painter. For

example, flip-vert takes a painter and produces a painter that draws its

image upside-down, and flip-horiz produces a painter that draws the

original painter’s image left-to-right reversed.

为了组合图像,我们使用各种操作从已有的画家构造新画家。例如,beside 操作接受两个画家,生成一个新的复合画家,该画家将第一个画家的图像绘制在框架的左半部分,将第二个画家的图像绘制在框架的右半部分。类似地,below 接受两个画家,生成一个复合画家,将第一个画家的图像绘制在第二个画家图像的下方。某些操作对单个画家进行变换以生成新画家。例如,flip-vert 接受一个画家,生成一个将其图像上下翻转绘制的画家;flip-horiz 则生成一个将原画家图像左右镜像绘制的画家。

Figure 2.12 shows the drawing of a painter called

wave4 that is built up in two stages starting from wave:

图 2.12 展示了名为 wave4 的画家的绘制结果,它从 wave 出发,经过两个阶段构建而成:

Figure 2.12: Creating a complex figure, starting from the wave painter of Figure 2.10.

图 2.12:从图 2.10 的 wave 画家出发,逐步构造复杂图形的过程。

In building up a complex image in this manner we are exploiting the fact that

painters are closed under the language’s means of combination. The

beside or below of two painters is itself a painter; therefore,

we can use it as an element in making more complex painters. As with building

up list structure using cons, the closure of our data under the means of

combination is crucial to the ability to create complex structures while using

only a few operations.

以这种方式构建复杂图像,正是利用了画家在该语言的组合方法下是封闭的这一事实。两个画家经 beside 或 below 组合后,其结果本身仍是一个画家;因此,我们可以将其用作构造更复杂画家的元素。如同用 cons 构建表结构,数据在组合方法下的封闭性对于仅凭少数几种操作就能创造复杂结构的能力至关重要。

Once we can combine painters, we would like to be able to abstract typical

patterns of combining painters. We will implement the painter operations as

Scheme procedures. This means that we don’t need a special abstraction

mechanism in the picture language: Since the means of combination are ordinary

Scheme procedures, we automatically have the capability to do anything with

painter operations that we can do with procedures. For example, we can

abstract the pattern in wave4 as

一旦能够组合画家,我们便希望对组合画家的典型模式加以抽象。我们将以 Scheme 过程的形式实现各种画家操作。这意味着在图像语言中无需专门的抽象机制:由于组合的方法就是普通的 Scheme 过程,我们自然拥有对画家操作执行任何过程可做之事的能力。例如,我们可以将 wave4 中的模式抽象为

and define wave4 as an instance of this pattern:

并将 wave4 定义为该模式的一个实例:

We can also define recursive operations. Here’s one that makes painters split

and branch towards the right as shown in Figure 2.13

and Figure 2.14:

我们还可以定义递归操作。下面是一个让画家向右分裂并分叉的操作,效果如图 2.13 和图 2.14 所示:

Figure 2.13: Recursive plans for right-split and corner-split.

图 2.13:right-split 与 corner-split 的递归构造方案。

We can produce balanced patterns by branching upwards as well as towards the

right (see Exercise 2.44, Figure 2.13 and Figure 2.14):

通过同时向上和向右分叉,我们可以生成均衡的图案(参见练习 2.44、图 2.13 和图 2.14):

Figure 2.14: The recursive operations right-split and corner-split applied to the painters wave and rogers. Combining four corner-split figures produces symmetric square-limit designs as shown in Figure 2.9.

图 2.14:将递归操作 right-split 和 corner-split 作用于画家 wave 和 rogers 的结果。将四个 corner-split 图形适当拼合,可得到如图 2.9 所示的对称的正方形极限图案。

By placing four copies of a corner-split appropriately, we obtain a

pattern called square-limit, whose application to wave and

rogers is shown in Figure 2.9:

通过将四个 corner-split 的副本适当排列,我们得到一种称为 square-limit 的图案,其作用于 wave 和 rogers 的效果如图 2.9 所示:

Racket #lang sicp
(define wave2 (beside wave (flip-vert wave)))
(define wave4 (below wave2 wave2))
Racket #lang sicp
(define (flipped-pairs painter)
 (let ((painter2
 (beside painter
 (flip-vert painter))))
 (below painter2 painter2)))
Racket #lang sicp
(define wave4 (flipped-pairs wave))
Racket #lang sicp
(define (right-split painter n)
 (if (= n 0)
 painter
 (let ((smaller (right-split painter
 (- n 1))))
 (beside painter
 (below smaller smaller)))))
Racket #lang sicp
(define (corner-split painter n)
 (if (= n 0)
 painter
 (let ((up (up-split painter (- n 1)))
 (right (right-split painter
 (- n 1))))
 (let ((top-left (beside up up))
 (bottom-right (below right
 right))
 (corner (corner-split painter
 (- n 1))))
 (beside (below painter top-left)
 (below bottom-right
 corner))))))
Racket #lang sicp
(define (square-limit painter n)
 (let ((quarter (corner-split painter n)))
 (let ((half (beside (flip-horiz quarter)
 quarter)))
 (below (flip-vert half) half))))