Structure and Interpretation of Computer Programs



Yüklə 2,71 Mb.
Pdf görüntüsü
səhifə35/222
tarix08.08.2018
ölçüsü2,71 Mb.
#61085
1   ...   31   32   33   34   35   36   37   38   ...   222

(define (make-rat n d)

  (let ((g (gcd n d)))

    (cons (/ n g) (/ d g))))

Now we have

(print-rat (add-rat one-third one-third))

2/3

as desired. This modification was accomplished by changing the constructor 

make-rat

 without


changing any of the procedures (such as 

add-rat


 and 

mul-rat


) that implement the actual 

operations.



Exercise 2.1.  Define a better version of 

make-rat


 that handles both positive and negative

arguments. 

Make-rat

 should normalize the sign so that if the rational number is positive, both the

numerator and denominator are positive, and if the rational number is negative, only the numerator is

negative. 



2.1.2  Abstraction Barriers

Before continuing with more examples of compound data and data abstraction, let us consider some of

the issues raised by the rational-number example. We defined the rational-number operations in terms

of a constructor 

make-rat

 and selectors 

numer

 and 


denom

. In general, the underlying idea of data

abstraction is to identify for each type of data object a basic set of operations in terms of which all

manipulations of data objects of that type will be expressed, and then to use only those operations in

manipulating the data.

We can envision the structure of the rational-number system as shown in figure 2.1. The horizontal

lines represent abstraction barriers that isolate different ‘‘levels’’ of the system. At each level, the

barrier separates the programs (above) that use the data abstraction from the programs (below) that

implement the data abstraction. Programs that use rational numbers manipulate them solely in terms of

the procedures supplied ‘‘for public use’’ by the rational-number package: 

add-rat



sub-rat



mul-rat


div-rat


, and 

equal-rat?

. These, in turn, are implemented solely in terms of the 

constructor and selectors 

make-rat

numer



, and 

denom


, which themselves are implemented in

terms of pairs. The details of how pairs are implemented are irrelevant to the rest of the

rational-number package so long as pairs can be manipulated by the use of 

cons


car


, and 

cdr


. In

effect, procedures at each level are the interfaces that define the abstraction barriers and connect the

different levels.



  

Figure 2.1:  Data-abstraction barriers in the rational-number package.

Figure 2.1:  Data-abstraction barriers in the rational-number package.

This simple idea has many advantages. One advantage is that it makes programs much easier to

maintain and to modify. Any complex data structure can be represented in a variety of ways with the

primitive data structures provided by a programming language. Of course, the choice of representation

influences the programs that operate on it; thus, if the representation were to be changed at some later

time, all such programs might have to be modified accordingly. This task could be time-consuming

and expensive in the case of large programs unless the dependence on the representation were to be

confined by design to a very few program modules.

For example, an alternate way to address the problem of reducing rational numbers to lowest terms is

to perform the reduction whenever we access the parts of a rational number, rather than when we

construct it. This leads to different constructor and selector procedures:

(define (make-rat n d)

  (cons n d))

(define (numer x)

  (let ((g (gcd (car x) (cdr x))))

    (/ (car x) g)))

(define (denom x)

  (let ((g (gcd (car x) (cdr x))))

    (/ (cdr x) g)))

The difference between this implementation and the previous one lies in when we compute the 

gcd

. If


in our typical use of rational numbers we access the numerators and denominators of the same rational

numbers many times, it would be preferable to compute the 

gcd

 when the rational numbers are



constructed. If not, we may be better off waiting until access time to compute the 

gcd


. In any case,

when we change from one representation to the other, the procedures 

add-rat



sub-rat



, and so on

do not have to be modified at all.

Constraining the dependence on the representation to a few interface procedures helps us design

programs as well as modify them, because it allows us to maintain the flexibility to consider alternate

implementations. To continue with our simple example, suppose we are designing a rational-number

package and we can’t decide initially whether to perform the 

gcd

 at construction time or at selection




time. The data-abstraction methodology gives us a way to defer that decision without losing the ability

to make progress on the rest of the system.



Exercise 2.2.  Consider the problem of representing line segments in a plane. Each segment is

represented as a pair of points: a starting point and an ending point. Define a constructor 

make-segment

 and selectors 

start-segment

 and 


end-segment

 that define the representation

of segments in terms of points. Furthermore, a point can be represented as a pair of numbers: the x

coordinate and the y coordinate. Accordingly, specify a constructor 

make-point

 and selectors 

x-point

 and 


y-point

 that define this representation. Finally, using your selectors and

constructors, define a procedure 

midpoint-segment

 that takes a line segment as argument and

returns its midpoint (the point whose coordinates are the average of the coordinates of the endpoints).

To try your procedures, you’ll need a way to print points:

(define (print-point p)

  (newline)

  (display "(")

  (display (x-point p))

  (display ",")

  (display (y-point p))

  (display ")"))



Exercise 2.3.  Implement a representation for rectangles in a plane. (Hint: You may want to make use

of exercise 2.2.) In terms of your constructors and selectors, create procedures that compute the

perimeter and the area of a given rectangle. Now implement a different representation for rectangles.

Can you design your system with suitable abstraction barriers, so that the same perimeter and area

procedures will work using either representation? 

2.1.3  What Is Meant by Data?

We began the rational-number implementation in section 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.

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

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.

5



Yüklə 2,71 Mb.

Dostları ilə paylaş:
1   ...   31   32   33   34   35   36   37   38   ...   222




Verilənlər bazası müəlliflik hüququ ilə müdafiə olunur ©genderi.org 2024
rəhbərliyinə müraciət

    Ana səhifə