Structure and Interpretation of Computer Programs



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

      guess

      (sqrt-iter (improve guess x) x)))

(define (good-enough? guess x)

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

(define (improve guess x)

  (average guess (/ x guess)))

The problem with this program is that the only procedure that is important to users of 

sqrt


 is 

sqrt


.

The other procedures (

sqrt-iter

good-enough?



, and 

improve


) only clutter up their minds.

They may not define any other procedure called 

good-enough?

 as part of another program to work

together with the square-root program, because 

sqrt


 needs it. The problem is especially severe in the

construction of large systems by many separate programmers. For example, in the construction of a

large library of numerical procedures, many numerical functions are computed as successive

approximations and thus might have procedures named 

good-enough?

 and 


improve

 as auxiliary

procedures. We would like to localize the subprocedures, hiding them inside 

sqrt


 so that 

sqrt


 could

coexist with other successive approximations, each having its own private 

good-enough?

procedure. To make this possible, we allow a procedure to have internal definitions that are local to

that procedure. For example, in the square-root problem we can write

(define (sqrt x)

  (define (good-enough? guess x)

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

  (define (improve guess x)

    (average guess (/ x guess)))

  (define (sqrt-iter guess x)

    (if (good-enough? guess x)

        guess

        (sqrt-iter (improve guess x) x)))

  (sqrt-iter 1.0 x))

Such nesting of definitions, called block structure, is basically the right solution to the simplest

name-packaging problem. But there is a better idea lurking here. In addition to internalizing the

definitions of the auxiliary procedures, we can simplify them. Since 

x

 is bound in the definition of 



sqrt

, the procedures 

good-enough?

improve



, and 

sqrt-iter

, which are defined internally

to 


sqrt

, are in the scope of 

x

. Thus, it is not necessary to pass 



x

 explicitly to each of these

procedures. Instead, we allow 

x

 to be a free variable in the internal definitions, as shown below. Then 



x

 gets its value from the argument with which the enclosing procedure 

sqrt

 is called. This discipline



is called lexical scoping.

27

(define (sqrt x)



  (define (good-enough? guess)

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

  (define (improve guess)

    (average guess (/ x guess)))

  (define (sqrt-iter guess)

    (if (good-enough? guess)

        guess

        (sqrt-iter (improve guess))))

  (sqrt-iter 1.0))



We will use block structure extensively to help us break up large programs into tractable pieces.

28

The idea of block structure originated with the programming language Algol 60. It appears in most



advanced programming languages and is an important tool for helping to organize the construction of

large programs.

4

 The characterization of numbers as ‘‘simple data’’ is a barefaced bluff. In fact, the treatment of



numbers is one of the trickiest and most confusing aspects of any programming language. Some

typical issues involved are these: Some computer systems distinguish integers, such as 2, from real 



numbers, such as 2.71. Is the real number 2.00 different from the integer 2? Are the arithmetic

operations used for integers the same as the operations used for real numbers? Does 6 divided by 2

produce 3, or 3.0? How large a number can we represent? How many decimal places of accuracy can

we represent? Is the range of integers the same as the range of real numbers? Above and beyond these

questions, of course, lies a collection of issues concerning roundoff and truncation errors -- the entire

science of numerical analysis. Since our focus in this book is on large-scale program design rather than

on numerical techniques, we are going to ignore these problems. The numerical examples in this

chapter will exhibit the usual roundoff behavior that one observes when using arithmetic operations

that preserve a limited number of decimal places of accuracy in noninteger operations. 

5

 Throughout this book, when we wish to emphasize the distinction between the input typed by the



user and the response printed by the interpreter, we will show the latter in slanted characters. 

6

 Lisp systems typically provide features to aid the user in formatting expressions. Two especially



useful features are one that automatically indents to the proper pretty-print position whenever a new

line is started and one that highlights the matching left parenthesis whenever a right parenthesis is

typed. 

7

 Lisp obeys the convention that every expression has a value. This convention, together with the old



reputation of Lisp as an inefficient language, is the source of the quip by Alan Perlis (paraphrasing

Oscar Wilde) that ‘‘Lisp programmers know the value of everything but the cost of nothing.’’ 

8

 In this book, we do not show the interpreter’s response to evaluating definitions, since this is highly



implementation-dependent. 

9

 Chapter 3 will show that this notion of environment is crucial, both for understanding how the



interpreter works and for implementing interpreters. 

10

 It may seem strange that the evaluation rule says, as part of the first step, that we should evaluate



the leftmost element of a combination, since at this point that can only be an operator such as 

+

 or 



*

representing a built-in primitive procedure such as addition or multiplication. We will see later that it

is useful to be able to work with combinations whose operators are themselves compound expressions. 

11

 Special syntactic forms that are simply convenient alternative surface structures for things that can



be written in more uniform ways are sometimes called syntactic sugar, to use a phrase coined by Peter

Landin. In comparison with users of other languages, Lisp programmers, as a rule, are less concerned

with matters of syntax. (By contrast, examine any Pascal manual and notice how much of it is devoted

to descriptions of syntax.) This disdain for syntax is due partly to the flexibility of Lisp, which makes

it easy to change surface syntax, and partly to the observation that many ‘‘convenient’’ syntactic

constructs, which make the language less uniform, end up causing more trouble than they are worth

when programs become large and complex. In the words of Alan Perlis, ‘‘Syntactic sugar causes

cancer of the semicolon.’’ 




Yüklə 2,71 Mb.

Dostları ilə paylaş:
1   ...   10   11   12   13   14   15   16   17   ...   222




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

    Ana səhifə