灯下 登录
计算机科学 / SICP / 2.2.4 Example: A Picture Language

Exercise 2.47 · 习题

Exercise 2.47: Here are two possible
constructors for frames:

(define (make-frame origin edge1 edge2)
(list origin edge1 edge2))

(define (make-frame origin edge1 edge2)
(cons origin (cons edge1 edge2)))

For each constructor supply the appropriate selectors to produce an
implementation for frames.

Painters

A painter is represented as a procedure that, given a frame as argument, draws
a particular image shifted and scaled to fit the frame. That is to say, if
p is a painter and f is a frame, then we produce p’s image
in f by calling p with f as argument.

The details of how primitive painters are implemented depend on the particular
characteristics of the graphics system and the type of image to be drawn. For
instance, suppose we have a procedure draw-line that draws a line on the
screen between two specified points. Then we can create painters for line
drawings, such as the wave painter in Figure 2.10, from lists of
line segments as follows:

(define (segments->painter segment-list)
(lambda (frame)
(for-each
(lambda (segment)
(draw-line
((frame-coord-map frame)
(start-segment segment))
((frame-coord-map frame)
(end-segment segment))))
segment-list)))

The segments are given using coordinates with respect to the unit square. For
each segment in the list, the painter transforms the segment endpoints with the
frame coordinate map and draws a line between the transformed points.

Representing painters as procedures erects a powerful abstraction barrier in

the picture language. We can create and intermix all sorts of primitive

painters, based on a variety of graphics capabilities. The details of their

implementation do not matter. Any procedure can serve as a painter, provided

that it takes a frame as argument and draws something scaled to fit the

frame.

练习 2.47:以下是框架的两种可能的构造函数:

(define (make-frame origin edge1 edge2)
(list origin edge1 edge2))

(define (make-frame origin edge1 edge2)
(cons origin (cons edge1 edge2)))

请为每种构造函数提供相应的选择函数,产生一个完整的框架实现。

画家

画家被表示为一个过程,给定一个框架作为参数,它在该框架内绘制经过平移和缩放以适合框架的特定图像。也就是说,若 p 是一个画家,f 是一个框架,则以 f 为参数调用 p 即可在 f 中产生 p 的图像。

基本画家的具体实现方式取决于图形系统的特性和所绘图像的类型。例如,假设我们有一个过程 draw-line,可在屏幕上的两个指定点之间画一条线段。那么,我们可以利用线段的表(如图 2.10 中的 wave 画家)按如下方式创建线段绘制的画家:

(define (segments->painter segment-list)
(lambda (frame)
(for-each
(lambda (segment)
(draw-line
((frame-coord-map frame)
(start-segment segment))
((frame-coord-map frame)
(end-segment segment))))
segment-list)))

各线段使用相对于单位正方形的坐标给出。对于表中的每条线段,画家用框架坐标映射变换线段端点,并在变换后的两点之间画一条线。

将画家表示为过程,在图形语言中建立了一道有力的抽象屏障。我们可以创建并混用各种基本画家,涵盖多种图形能力。其实现细节无关紧要。任何过程都可以充当画家,只要它接受一个框架作为参数,并绘制经缩放以适合该框架的某些内容。

Racket #lang sicp
(define (make-frame origin edge1 edge2)
 (list origin edge1 edge2))

(define (make-frame origin edge1 edge2)
 (cons origin (cons edge1 edge2)))
Racket #lang sicp
(define (segments->painter segment-list)
 (lambda (frame)
 (for-each
 (lambda (segment)
 (draw-line
 ((frame-coord-map frame)
 (start-segment segment))
 ((frame-coord-map frame)
 (end-segment segment))))
 segment-list)))