Structure and Interpretation of Computer Programs



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

our minds. It would be much better if we could ‘‘glue together’’ a numerator and denominator to form

a pair -- a compound data object -- that our programs could manipulate in a way that would be

consistent with regarding a rational number as a single conceptual unit.

The use of compound data also enables us to increase the modularity of our programs. If we can

manipulate rational numbers directly as objects in their own right, then we can separate the part of our

program that deals with rational numbers per se from the details of how rational numbers may be

represented as pairs of integers. The general technique of isolating the parts of a program that deal

with how data objects are represented from the parts of a program that deal with how data objects are

used is a powerful design methodology called data abstraction. We will see how data abstraction

makes programs much easier to design, maintain, and modify.

The use of compound data leads to a real increase in the expressive power of our programming

language. Consider the idea of forming a ‘‘linear combination’’ ax + by. We might like to write a

procedure that would accept abx, and y as arguments and return the value of ax + by. This presents

no difficulty if the arguments are to be numbers, because we can readily define the procedure

(define (linear-combination a b x y) 

  (+ (* a x) (* b y)))

But suppose we are not concerned only with numbers. Suppose we would like to express, in

procedural terms, the idea that one can form linear combinations whenever addition and multiplication

are defined -- for rational numbers, complex numbers, polynomials, or whatever. We could express

this as a procedure of the form

(define (linear-combination a b x y)     

  (add (mul a x) (mul b y))) 

where 

add


 and 

mul


 are not the primitive procedures 

+

 and 



*

 but rather more complex things that will

perform the appropriate operations for whatever kinds of data we pass in as the arguments 

a



b

x



, and 

y

. The key point is that the only thing 



linear-combination

 should need to know about 

a



b



x

,



and 

y

 is that the procedures 



add

 and 


mul

 will perform the appropriate manipulations. From the

perspective of the procedure 

linear-combination

, it is irrelevant what 

a



b

x



, and 

y

 are and



even more irrelevant how they might happen to be represented in terms of more primitive data. This

same example shows why it is important that our programming language provide the ability to

manipulate compound objects directly: Without this, there is no way for a procedure such as 

linear-combination

 to pass its arguments along to 

add


 and 

mul


 without having to know their

detailed structure.

1

 We begin this chapter by implementing the rational-number arithmetic system



mentioned above. This will form the background for our discussion of compound data and data

abstraction. As with compound procedures, the main issue to be addressed is that of abstraction as a

technique for coping with complexity, and we will see how data abstraction enables us to erect suitable 

abstraction barriers between different parts of a program.

We will see that the key to forming compound data is that a programming language should provide

some kind of ‘‘glue’’ so that data objects can be combined to form more complex data objects. There

are many possible kinds of glue. Indeed, we will discover how to form compound data using no

special ‘‘data’’ operations at all, only procedures. This will further blur the distinction between

‘‘procedure’’ and ‘‘data,’’ which was already becoming tenuous toward the end of chapter 1. We will

also explore some conventional techniques for representing sequences and trees. One key idea in

dealing with compound data is the notion of closure -- that the glue we use for combining data objects

should allow us to combine not only primitive data objects, but compound data objects as well.

Another key idea is that compound data objects can serve as conventional interfaces for combining




program modules in mix-and-match ways. We illustrate some of these ideas by presenting a simple

graphics language that exploits closure.

We will then augment the representational power of our language by introducing symbolic expressions

-- data whose elementary parts can be arbitrary symbols rather than only numbers. We explore various

alternatives for representing sets of objects. We will find that, just as a given numerical function can

be computed by many different computational processes, there are many ways in which a given data

structure can be represented in terms of simpler objects, and the choice of representation can have

significant impact on the time and space requirements of processes that manipulate the data. We will

investigate these ideas in the context of symbolic differentiation, the representation of sets, and the

encoding of information.

Next we will take up the problem of working with data that may be represented differently by different

parts of a program. This leads to the need to implement generic operations, which must handle many

different types of data. Maintaining modularity in the presence of generic operations requires more

powerful abstraction barriers than can be erected with simple data abstraction alone. In particular, we

introduce data-directed programming as a technique that allows individual data representations to be

designed in isolation and then combined additively (i.e., without modification). To illustrate the power

of this approach to system design, we close the chapter by applying what we have learned to the

implementation of a package for performing symbolic arithmetic on polynomials, in which the

coefficients of the polynomials can be integers, rational numbers, complex numbers, and even other 

polynomials.

1

 The ability to directly manipulate procedures provides an analogous increase in the expressive



power of a programming language. For example, in section 1.3.1 we introduced the 

sum


 procedure,

which takes a procedure 

term

 as an argument and computes the sum of the values of 



term

 over


some specified interval. In order to define 

sum


, it is crucial that we be able to speak of a procedure

such as 


term

 as an entity in its own right, without regard for how 

term

 might be expressed with



more primitive operations. Indeed, if we did not have the notion of ‘‘a procedure,’’ it is doubtful that

we would ever even think of the possibility of defining an operation such as 

sum

. Moreover, insofar as



performing the summation is concerned, the details of how 

term


 may be constructed from more

primitive operations are irrelevant. 

[Go to first, previous, next page;   contents;   index]



Yüklə 2,71 Mb.

Dostları ilə paylaş:
1   ...   29   30   31   32   33   34   35   36   ...   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ə