Structure and Interpretation of Computer Programs



Yüklə 2,71 Mb.
Pdf görüntüsü
səhifə43/222
tarix08.08.2018
ölçüsü2,71 Mb.
#61085
1   ...   39   40   41   42   43   44   45   46   ...   222

Accumulations can be implemented by 

(define (accumulate op initial sequence)

  (if (null? sequence)

      initial

      (op (car sequence)

          (accumulate op initial (cdr sequence)))))

(accumulate + 0 (list 1 2 3 4 5))

15

(accumulate * 1 (list 1 2 3 4 5))



120

(accumulate cons nil (list 1 2 3 4 5))



(1 2 3 4 5)

All that remains to implement signal-flow diagrams is to enumerate the sequence of elements to be

processed. For 

even-fibs

, we need to generate the sequence of integers in a given range, which we

can do as follows: 

(define (enumerate-interval low high)

  (if (> low high)

      nil

      (cons low (enumerate-interval (+ low 1) high))))

(enumerate-interval 2 7)

(2 3 4 5 6 7)

To enumerate the leaves of a tree, we can use

14

 

(define (enumerate-tree tree)



  (cond ((null? tree) nil)

        ((not (pair? tree)) (list tree))

        (else (append (enumerate-tree (car tree))

                      (enumerate-tree (cdr tree))))))

(enumerate-tree (list 1 (list 2 (list 3 4)) 5))

(1 2 3 4 5)

Now we can reformulate 

sum-odd-squares

 and 


even-fibs

 as in the signal-flow diagrams. For 

sum-odd-squares

, we enumerate the sequence of leaves of the tree, filter this to keep only the odd

numbers in the sequence, square each element, and sum the results: 

(define (sum-odd-squares tree)

  (accumulate +

              0

              (map square

                   (filter odd?

                           (enumerate-tree tree)))))

For 


even-fibs

, we enumerate the integers from 0 to n, generate the Fibonacci number for each of

these integers, filter the resulting sequence to keep only the even elements, and accumulate the results

into a list: 




(define (even-fibs n)

  (accumulate cons

              nil

              (filter even?

                      (map fib

                           (enumerate-interval 0 n)))))

The value of expressing programs as sequence operations is that this helps us make program designs

that are modular, that is, designs that are constructed by combining relatively independent pieces. We

can encourage modular design by providing a library of standard components together with a

conventional interface for connecting the components in flexible ways.

Modular construction is a powerful strategy for controlling complexity in engineering design. In real

signal-processing applications, for example, designers regularly build systems by cascading elements

selected from standardized families of filters and transducers. Similarly, sequence operations provide a

library of standard program elements that we can mix and match. For instance, we can reuse pieces

from the 

sum-odd-squares

 and 

even-fibs



 procedures in a program that constructs a list of the

squares of the first n + 1 Fibonacci numbers: 

(define (list-fib-squares n)

  (accumulate cons

              nil

              (map square

                   (map fib

                        (enumerate-interval 0 n)))))

(list-fib-squares 10)

(0 1 1 4 9 25 64 169 441 1156 3025)

We can rearrange the pieces and use them in computing the product of the odd integers in a sequence: 

(define (product-of-squares-of-odd-elements sequence)

  (accumulate *

              1

              (map square

                   (filter odd? sequence))))

(product-of-squares-of-odd-elements (list 1 2 3 4 5))



225

We can also formulate conventional data-processing applications in terms of sequence operations.

Suppose we have a sequence of personnel records and we want to find the salary of the highest-paid

programmer. Assume that we have a selector 

salary

 that returns the salary of a record, and a



predicate 

programmer?

 that tests if a record is for a programmer. Then we can write 

(define (salary-of-highest-paid-programmer records)

  (accumulate max

              0

              (map salary

                   (filter programmer? records))))




These examples give just a hint of the vast range of operations that can be expressed as sequence 

operations.

15

Sequences, implemented here as lists, serve as a conventional interface that permits us to combine



processing modules. Additionally, when we uniformly represent structures as sequences, we have

localized the data-structure dependencies in our programs to a small number of sequence operations.

By changing these, we can experiment with alternative representations of sequences, while leaving the

overall design of our programs intact. We will exploit this capability in section 3.5, when we

generalize the sequence-processing paradigm to admit infinite sequences.

Exercise 2.33.  Fill in the missing expressions to complete the following definitions of some basic

list-manipulation operations as accumulations: 

(define (map p sequence)

  (accumulate (lambda (x y) <??>) nil sequence))

(define (append seq1 seq2)

  (accumulate cons <??> <??>))

(define (length sequence)

  (accumulate <??> 0 sequence))



Exercise 2.34.  Evaluating a polynomial in x at a given value of x can be formulated as an

accumulation. We evaluate the polynomial 

using a well-known algorithm called Horner’s rule, which structures the computation as 

In other words, we start with a



n

, multiply by x, add a



n-1

, multiply by x, and so on, until we reach 



a

0

.



16

 Fill in the following template to produce a procedure that evaluates a polynomial using

Horner’s rule. Assume that the coefficients of the polynomial are arranged in a sequence, from a

0

through a



n

(define (horner-eval x coefficient-sequence)



  (accumulate (lambda (this-coeff higher-terms) <??>)

              0

              coefficient-sequence))

For example, to compute 1 + 3x + 5x

3

 + x



5

 at x = 2 you would evaluate 

(horner-eval 2 (list 1 3 0 5 0 1))

Exercise 2.35.  Redefine 

count-leaves

 from section 2.2.2 as an accumulation: 

(define (count-leaves t)

  (accumulate <??> <??> (map <??> <??>)))

Exercise 2.36.  The procedure 

accumulate-n

 is similar to 

accumulate

 except that it takes as its

third argument a sequence of sequences, which are all assumed to have the same number of elements.

It applies the designated accumulation procedure to combine all the first elements of the sequences, all

the second elements of the sequences, and so on, and returns a sequence of the results. For instance, if 




Yüklə 2,71 Mb.

Dostları ilə paylaş:
1   ...   39   40   41   42   43   44   45   46   ...   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ə