Structure and Interpretation of Computer Programs



Yüklə 2,71 Mb.
Pdf görüntüsü
səhifə13/222
tarix08.08.2018
ölçüsü2,71 Mb.
#61085
1   ...   9   10   11   12   13   14   15   16   ...   222

Figure 1.2:  Procedural decomposition of the 

sqrt


 program.

Figure 1.2:  Procedural decomposition of the 

sqrt


 program.

The importance of this decomposition strategy is not simply that one is dividing the program into

parts. After all, we could take any large program and divide it into parts -- the first ten lines, the next

ten lines, the next ten lines, and so on. Rather, it is crucial that each procedure accomplishes an

identifiable task that can be used as a module in defining other procedures. For example, when we

define the 

good-enough?

 procedure in terms of 

square

, we are able to regard the 



square

procedure as a ‘‘black box.’’ We are not at that moment concerned with how the procedure computes

its result, only with the fact that it computes the square. The details of how the square is computed can

be suppressed, to be considered at a later time. Indeed, as far as the 

good-enough?

 procedure is

concerned, 

square


 is not quite a procedure but rather an abstraction of a procedure, a so-called 

procedural abstraction. At this level of abstraction, any procedure that computes the square is equally 

good.


Thus, considering only the values they return, the following two procedures for squaring a number

should be indistinguishable. Each takes a numerical argument and produces the square of that number

as the value.

25

(define (square x) (* x x))



(define (square x) 

  (exp (double (log x))))

(define (double x) (+ x x))

So a procedure definition should be able to suppress detail. The users of the procedure may not have

written the procedure themselves, but may have obtained it from another programmer as a black box.

A user should not need to know how the procedure is implemented in order to use it.



Local names

One detail of a procedure’s implementation that should not matter to the user of the procedure is the

implementer’s choice of names for the procedure’s formal parameters. Thus, the following procedures

should not be distinguishable:




(define (square x) (* x x))

(define (square y) (* y y))

This principle -- that the meaning of a procedure should be independent of the parameter names used

by its author -- seems on the surface to be self-evident, but its consequences are profound. The

simplest consequence is that the parameter names of a procedure must be local to the body of the

procedure. For example, we used 

square

 in the definition of 



good-enough?

 in our square-root 

procedure:

(define (good-enough? guess x)

  (< (abs (- (square guess) x)) 0.001))

The intention of the author of 

good-enough?

 is to determine if the square of the first argument is

within a given tolerance of the second argument. We see that the author of 

good-enough?

 used the

name 


guess

 to refer to the first argument and 

x

 to refer to the second argument. The argument of 



square

 is 


guess

. If the author of 

square

 used 


x

 (as above) to refer to that argument, we see that

the 

x

 in 



good-enough?

 must be a different 

x

 than the one in 



square

. Running the procedure 

square

 must not affect the value of 



x

 that is used by 

good-enough?

, because that value of 

x

 may


be needed by 

good-enough?

 after 

square


 is done computing.

If the parameters were not local to the bodies of their respective procedures, then the parameter 

x

 in 


square

 could be confused with the parameter 

x

 in 


good-enough?

, and the behavior of 

good-enough?

 would depend upon which version of 

square

 we used. Thus, 



square

 would not

be the black box we desired.

A formal parameter of a procedure has a very special role in the procedure definition, in that it doesn’t

matter what name the formal parameter has. Such a name is called a bound variable, and we say that

the procedure definition binds its formal parameters. The meaning of a procedure definition is

unchanged if a bound variable is consistently renamed throughout the definition.

26

 If a variable is not



bound, we say that it is free. The set of expressions for which a binding defines a name is called the 

scope of that name. In a procedure definition, the bound variables declared as the formal parameters of

the procedure have the body of the procedure as their scope.

In the definition of 

good-enough?

 above, 

guess


 and 

x

 are bound variables but 



<

-



abs


, and 

square


 are free. The meaning of 

good-enough?

 should be independent of the names we choose

for 


guess

 and 


x

 so long as they are distinct and different from 



<

-



abs


, and 

square


. (If we

renamed 


guess

 to 


abs

 we would have introduced a bug by capturing the variable 

abs

. It would



have changed from free to bound.) The meaning of 

good-enough?

 is not independent of the names

of its free variables, however. It surely depends upon the fact (external to this definition) that the

symbol 

abs


 names a procedure for computing the absolute value of a number. 

Good-enough?

 will

compute a different function if we substitute 



cos

 for 


abs

 in its definition.



Internal definitions and block structure

We have one kind of name isolation available to us so far: The formal parameters of a procedure are

local to the body of the procedure. The square-root program illustrates another way in which we would

like to control the use of names. The existing program consists of separate procedures:

(define (sqrt x)

  (sqrt-iter 1.0 x))

(define (sqrt-iter guess x)

  (if (good-enough? guess x)




Yüklə 2,71 Mb.

Dostları ilə paylaş:
1   ...   9   10   11   12   13   14   15   16   ...   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ə