mirror of
https://github.com/correl/sicp.git
synced 2024-11-27 11:09:58 +00:00
993 lines
31 KiB
Org Mode
993 lines
31 KiB
Org Mode
#+BEGIN_HTML
|
|
---
|
|
title: 2.2 - Hierarchical Data and the Closure Property
|
|
layout: org
|
|
---
|
|
#+END_HTML
|
|
|
|
* Representing Sequences
|
|
** List Operations
|
|
*** Exercise 2.17
|
|
Define a procedure `last-pair' that returns the
|
|
list that contains only the last element of a given (nonempty)
|
|
list:
|
|
|
|
#+begin_src scheme
|
|
(last-pair (list 23 72 149 34))
|
|
(34)
|
|
#+end_src
|
|
|
|
--------------------------------------------------------------------
|
|
|
|
#+begin_src scheme :tangle yes
|
|
;; -------------------------------------------------------------------
|
|
;; Exercise 2.17
|
|
;; -------------------------------------------------------------------
|
|
|
|
(define (last-pair list)
|
|
(cond ((null? list) ())
|
|
((null? (cdr list)) list)
|
|
(else (last-pair (cdr list)))))
|
|
#+end_src
|
|
*** Exercise 2.18
|
|
Define a procedure `reverse' that takes a list as
|
|
argument and returns a list of the same elements in reverse order:
|
|
|
|
#+begin_src scheme
|
|
(reverse (list 1 4 9 16 25))
|
|
(25 16 9 4 1)
|
|
#+end_src
|
|
|
|
--------------------------------------------------------------------
|
|
|
|
#+begin_src scheme :tangle yes
|
|
;; -------------------------------------------------------------------
|
|
;; Exercise 2.18
|
|
;; -------------------------------------------------------------------
|
|
|
|
(define (reverse list)
|
|
(define (iter original new)
|
|
(if (null? original) new
|
|
(let ((head (car original))
|
|
(tail (cdr original)))
|
|
(iter tail (cons head new)))))
|
|
(iter list ()))
|
|
#+end_src
|
|
|
|
*** Exercise 2.19
|
|
Consider the change-counting program of section
|
|
*Note 1-2-2::. It would be nice to be able to easily change the
|
|
currency used by the program, so that we could compute the number
|
|
of ways to change a British pound, for example. As the program is
|
|
written, the knowledge of the currency is distributed partly into
|
|
the procedure `first-denomination' and partly into the procedure
|
|
`count-change' (which knows that there are five kinds of U.S.
|
|
coins). It would be nicer to be able to supply a list of coins to
|
|
be used for making change.
|
|
|
|
We want to rewrite the procedure `cc' so that its second argument
|
|
is a list of the values of the coins to use rather than an integer
|
|
specifying which coins to use. We could then have lists that
|
|
defined each kind of currency:
|
|
|
|
#+begin_src scheme :tangle yes
|
|
;; -------------------------------------------------------------------
|
|
;; Exercise 2.19
|
|
;; -------------------------------------------------------------------
|
|
|
|
(define us-coins (list 50 25 10 5 1))
|
|
|
|
(define uk-coins (list 100 50 20 10 5 2 1 0.5))
|
|
#+end_src
|
|
|
|
We could then call `cc' as follows:
|
|
|
|
#+begin_src scheme
|
|
(cc 100 us-coins)
|
|
292
|
|
#+end_src
|
|
|
|
To do this will require changing the program `cc' somewhat. It
|
|
will still have the same form, but it will access its second
|
|
argument differently, as follows:
|
|
|
|
#+begin_src scheme :tangle yes
|
|
(define (cc amount coin-values)
|
|
(cond ((= amount 0) 1)
|
|
((or (< amount 0) (no-more? coin-values)) 0)
|
|
(else
|
|
(+ (cc amount
|
|
(except-first-denomination coin-values))
|
|
(cc (- amount
|
|
(first-denomination coin-values))
|
|
coin-values)))))
|
|
#+end_src
|
|
|
|
Define the procedures `first-denomination',
|
|
`except-first-denomination', and `no-more?' in terms of primitive
|
|
operations on list structures. Does the order of the list
|
|
`coin-values' affect the answer produced by `cc'? Why or why not?
|
|
|
|
----------------------------------------------------------------------
|
|
|
|
#+begin_src scheme :tangle yes
|
|
(define first-denomination car)
|
|
(define except-first-denomination cdr)
|
|
(define no-more? null?)
|
|
#+end_src
|
|
|
|
*** Exercise 2.20
|
|
The procedures `+', `*', and `list' take
|
|
arbitrary numbers of arguments. One way to define such procedures
|
|
is to use `define' with notation "dotted-tail notation". In a
|
|
procedure definition, a parameter list that has a dot before the
|
|
last parameter name indicates that, when the procedure is called,
|
|
the initial parameters (if any) will have as values the initial
|
|
arguments, as usual, but the final parameter's value will be a "list"
|
|
of any remaining arguments. For instance, given the definition
|
|
|
|
#+begin_src scheme
|
|
(define (f x y . z) <BODY>)
|
|
#+end_src
|
|
|
|
the procedure `f' can be called with two or more arguments. If we
|
|
evaluate
|
|
|
|
#+begin_src scheme
|
|
(f 1 2 3 4 5 6)
|
|
#+end_src
|
|
|
|
then in the body of `f', `x' will be 1, `y' will be 2, and `z'
|
|
will be the list `(3 4 5 6)'. Given the definition
|
|
|
|
#+begin_src scheme
|
|
(define (g . w) <BODY>)
|
|
#+end_src
|
|
|
|
the procedure `g' can be called with zero or more arguments. If we
|
|
evaluate
|
|
|
|
#+begin_src scheme
|
|
(g 1 2 3 4 5 6)
|
|
#+end_src
|
|
|
|
then in the body of `g', `w' will be the list `(1 2 3 4 5 6)'.(4)
|
|
|
|
Use this notation to write a procedure `same-parity' that takes
|
|
one or more integers and returns a list of all the arguments that
|
|
have the same even-odd parity as the first argument. For example,
|
|
|
|
#+begin_src scheme
|
|
(same-parity 1 2 3 4 5 6 7)
|
|
(1 3 5 7)
|
|
|
|
(same-parity 2 3 4 5 6 7)
|
|
(2 4 6)
|
|
#+end_src
|
|
|
|
----------------------------------------------------------------------
|
|
|
|
#+begin_src scheme :tangle yes
|
|
;; -------------------------------------------------------------------
|
|
;; Exercise 2.20
|
|
;; -------------------------------------------------------------------
|
|
|
|
(define (same-parity n . rest)
|
|
(define (iter predicate original filtered)
|
|
(cond ((null? original) filtered)
|
|
((predicate (car original))
|
|
(iter predicate
|
|
(cdr original)
|
|
(append filtered (list (car original)))))
|
|
(else (iter predicate
|
|
(cdr original)
|
|
filtered))))
|
|
(iter (if (even? n) even? odd?)
|
|
(cons n rest)
|
|
'()))
|
|
#+end_src
|
|
|
|
** Mapping over lists
|
|
*** Exercise 2.21:
|
|
The procedure `square-list' takes a list of numbers as argument
|
|
and returns a list of the squares of those numbers.
|
|
|
|
#+begin_src scheme
|
|
(square-list (list 1 2 3 4))
|
|
(1 4 9 16)
|
|
#+end_src
|
|
|
|
Here are two different definitions of `square-list'. Complete
|
|
both of them by filling in the missing expressions:
|
|
|
|
#+begin_src scheme
|
|
(define (square-list items)
|
|
(if (null? items)
|
|
nil
|
|
(cons <??> <??>)))
|
|
|
|
(define (square-list items)
|
|
(map <??> <??>))
|
|
#+end_src
|
|
|
|
----------------------------------------------------------------------
|
|
|
|
#+begin_src scheme :tangle yes
|
|
;; -------------------------------------------------------------------
|
|
;; Exercise 2.21
|
|
;; -------------------------------------------------------------------
|
|
|
|
(define (square-list items)
|
|
(if (null? items)
|
|
'()
|
|
(cons (* (car items) (car items)) (square-list (cdr items)))))
|
|
|
|
(define (square-list items)
|
|
(map (lambda (x) (* x x))
|
|
items))
|
|
#+end_src
|
|
|
|
*** Exercise 2.22:
|
|
Louis Reasoner tries to rewrite the first `square-list' procedure
|
|
of *Note Exercise 2-21:: so that it evolves an iterative process:
|
|
|
|
#+begin_src scheme
|
|
(define (square-list items)
|
|
(define (iter things answer)
|
|
(if (null? things)
|
|
answer
|
|
(iter (cdr things)
|
|
(cons (square (car things))
|
|
answer))))
|
|
(iter items nil))
|
|
#+end_src
|
|
|
|
Unfortunately, defining `square-list' this way produces the answer
|
|
list in the reverse order of the one desired. Why?
|
|
|
|
Louis then tries to fix his bug by interchanging the arguments to
|
|
`cons':
|
|
|
|
#+begin_src scheme
|
|
(define (square-list items)
|
|
(define (iter things answer)
|
|
(if (null? things)
|
|
answer
|
|
(iter (cdr things)
|
|
(cons answer
|
|
(square (car things))))))
|
|
(iter items nil))
|
|
#+end_src
|
|
|
|
This doesn't work either. Explain.
|
|
|
|
----------------------------------------------------------------------
|
|
|
|
The first iterative rewrite reads the items from first to last,
|
|
but builds the list last to first (cons effectively prepends the
|
|
answer to the list of results).
|
|
|
|
The second version attempts to reverse the arguments of cons,
|
|
however this doesn't build a proper list. Normally, a list is a
|
|
value paired with a list in the second slot. This pairs a list
|
|
with a value in the second slot.
|
|
|
|
*** Exercise 2.23
|
|
The procedure `for-each' is similar to `map'. It takes as
|
|
arguments a procedure and a list of elements. However, rather
|
|
than forming a list of the results, `for-each' just applies the
|
|
procedure to each of the elements in turn, from left to right.
|
|
The values returned by applying the procedure to the elements are
|
|
not used at all--`for-each' is used with procedures that perform
|
|
an action, such as printing. For example,
|
|
|
|
#+begin_src scheme
|
|
(for-each (lambda (x) (newline) (display x))
|
|
(list 57 321 88))
|
|
57
|
|
321
|
|
88
|
|
#+end_src
|
|
|
|
The value returned by the call to `for-each' (not illustrated
|
|
above) can be something arbitrary, such as true. Give an
|
|
implementation of `for-each'.
|
|
|
|
----------------------------------------------------------------------
|
|
|
|
#+begin_src scheme :tangle yes
|
|
;; -------------------------------------------------------------------
|
|
;; Exercise 2.23
|
|
;; -------------------------------------------------------------------
|
|
|
|
(define (for-each fun list)
|
|
(if (null? list)
|
|
#t
|
|
))
|
|
|
|
#+end_src
|
|
* Hierarchical Structures
|
|
** Exercise 2.24
|
|
Suppose we evaluate the expression `(list 1 (list
|
|
2 (list 3 4)))'. Give the result printed by the interpreter, the
|
|
corresponding box-and-pointer structure, and the interpretation of
|
|
this as a tree (as in *Note Figure 2-6::).
|
|
|
|
-------------------------------------------------------------------
|
|
|
|
#+begin_src scheme :tangle yes
|
|
;; -------------------------------------------------------------------
|
|
;; Exercise 2.24
|
|
;; -------------------------------------------------------------------
|
|
|
|
'(1 (2 (3 4)))
|
|
|
|
;; [ * | * ]
|
|
;; ↓ ↓
|
|
;; 1 [ * | * ]
|
|
;; ↓ ↓
|
|
;; 2 [ * | * ] → [ * | / ]
|
|
;; ↓ ↓
|
|
;; 3 4
|
|
|
|
;; *
|
|
;; / \
|
|
;; 1 *
|
|
;; / \
|
|
;; 2 *
|
|
;; / \
|
|
;; 3 4
|
|
#+end_src
|
|
|
|
** Exercise 2.25
|
|
Give combinations of `car's and `cdr's that will
|
|
pick 7 from each of the following lists:
|
|
|
|
#+begin_src scheme
|
|
(1 3 (5 7) 9)
|
|
|
|
((7))
|
|
|
|
(1 (2 (3 (4 (5 (6 7))))))
|
|
#+end_src
|
|
|
|
----------------------------------------------------------------------
|
|
|
|
#+begin_src scheme :tangle yes
|
|
;; -------------------------------------------------------------------
|
|
;; Exercise 2.25
|
|
;; -------------------------------------------------------------------
|
|
|
|
(car (cdr (car (cdr (cdr '(1 3 (5 7) 9))))))
|
|
|
|
(car (car '((7))))
|
|
|
|
(car (cdr (car (cdr (car (cdr (car (cdr (car (cdr (car (cdr '(1 (2 (3 (4 (5 (6 7))))))))))))))))))
|
|
#+end_src
|
|
|
|
** Exercise 2.26
|
|
Suppose we define `x' and `y' to be two lists:
|
|
|
|
#+begin_src scheme
|
|
(define x (list 1 2 3))
|
|
|
|
(define y (list 4 5 6))
|
|
#+end_src
|
|
|
|
What result is printed by the interpreter in response to
|
|
evaluating each of the following expressions:
|
|
|
|
#+begin_src scheme
|
|
(append x y)
|
|
|
|
(cons x y)
|
|
|
|
(list x y)
|
|
#+end_src
|
|
|
|
----------------------------------------------------------------------
|
|
|
|
#+begin_src scheme
|
|
;; -------------------------------------------------------------------
|
|
;; Exercise 2.26
|
|
;; -------------------------------------------------------------------
|
|
|
|
;; (append x y)
|
|
'(1 2 3 4 5 6)
|
|
|
|
;; (cons x y)
|
|
'((1 2 3) 4 5 6)
|
|
|
|
;; (list x y)
|
|
'((1 2 3) (4 5 6))
|
|
#+end_src
|
|
|
|
** Exercise 2.27
|
|
Modify your `reverse' procedure of *Note Exercise
|
|
2-18:: to produce a `deep-reverse' procedure that takes a list as
|
|
argument and returns as its value the list with its elements
|
|
reversed and with all sublists deep-reversed as well. For example,
|
|
|
|
#+begin_src scheme
|
|
(define x (list (list 1 2) (list 3 4)))
|
|
|
|
x
|
|
((1 2) (3 4))
|
|
|
|
(reverse x)
|
|
((3 4) (1 2))
|
|
|
|
(deep-reverse x)
|
|
((4 3) (2 1))
|
|
#+end_src
|
|
|
|
----------------------------------------------------------------------
|
|
|
|
#+begin_src scheme :tangle yes
|
|
;; -------------------------------------------------------------------
|
|
;; Exercise 2.27
|
|
;; -------------------------------------------------------------------
|
|
|
|
(define (deep-reverse list)
|
|
(define (iter original new)
|
|
(if (null? original) new
|
|
(let ((head (car original))
|
|
(tail (cdr original)))
|
|
(iter tail (cons
|
|
(if (pair? head)
|
|
(deep-reverse head)
|
|
head)
|
|
new)))))
|
|
(iter list ()))
|
|
|
|
#+end_src
|
|
|
|
** Exercise 2.28
|
|
Write a procedure `fringe' that takes as argument
|
|
a tree (represented as a list) and returns a list whose elements
|
|
are all the leaves of the tree arranged in left-to-right order.
|
|
For example,
|
|
|
|
#+begin_src scheme
|
|
(define x (list (list 1 2) (list 3 4)))
|
|
|
|
(fringe x)
|
|
(1 2 3 4)
|
|
|
|
(fringe (list x x))
|
|
(1 2 3 4 1 2 3 4)
|
|
#+end_src
|
|
|
|
----------------------------------------------------------------------
|
|
|
|
#+begin_src scheme
|
|
(define (fringe tree)
|
|
(define (iter original new)
|
|
(if (null? original) new
|
|
(let ((head (car original))
|
|
(tail (cdr original)))
|
|
(if (pair? head)
|
|
(iter (append head tail) new)
|
|
(iter tail (cons head new))))))
|
|
(iter (deep-reverse tree) '()))
|
|
#+end_src
|
|
|
|
** Exercise 2.29
|
|
A binary mobile consists of two branches, a left
|
|
branch and a right branch. Each branch is a rod of a certain
|
|
length, from which hangs either a weight or another binary mobile.
|
|
We can represent a binary mobile using compound data by
|
|
constructing it from two branches (for example, using `list'):
|
|
|
|
#+begin_src scheme
|
|
(define (make-mobile left right)
|
|
(list left right))
|
|
#+end_src
|
|
|
|
A branch is constructed from a `length' (which must be a number)
|
|
together with a `structure', which may be either a number
|
|
(representing a simple weight) or another mobile:
|
|
|
|
#+begin_src scheme
|
|
(define (make-branch length structure)
|
|
(list length structure))
|
|
#+end_src
|
|
|
|
a. Write the corresponding selectors `left-branch' and
|
|
`right-branch', which return the branches of a mobile, and
|
|
`branch-length' and `branch-structure', which return the
|
|
components of a branch.
|
|
|
|
b. Using your selectors, define a procedure `total-weight' that
|
|
returns the total weight of a mobile.
|
|
|
|
c. A mobile is said to be "balanced" if the torque applied by
|
|
its top-left branch is equal to that applied by its top-right
|
|
branch (that is, if the length of the left rod multiplied by
|
|
the weight hanging from that rod is equal to the
|
|
corresponding product for the right side) and if each of the
|
|
submobiles hanging off its branches is balanced. Design a
|
|
predicate that tests whether a binary mobile is balanced.
|
|
|
|
d. Suppose we change the representation of mobiles so that the
|
|
constructors are
|
|
|
|
#+begin_src scheme
|
|
(define (make-mobile left right)
|
|
(cons left right))
|
|
|
|
(define (make-branch length structure)
|
|
(cons length structure))
|
|
#+end_src
|
|
|
|
How much do you need to change your programs to convert to
|
|
the new representation?
|
|
|
|
----------------------------------------------------------------------
|
|
|
|
#+begin_src scheme :tangle yes
|
|
;; -------------------------------------------------------------------
|
|
;; Exercise 2.29
|
|
;; -------------------------------------------------------------------
|
|
|
|
(define (make-mobile left right)
|
|
(list left right))
|
|
|
|
(define (make-branch length structure)
|
|
(list length structure))
|
|
|
|
(define left-branch car)
|
|
(define right-branch cadr)
|
|
|
|
(define branch-length car)
|
|
(define branch-structure cadr)
|
|
|
|
;; Test Data
|
|
;; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
(define (make-test-mobile)
|
|
(make-mobile
|
|
(make-branch 3 4)
|
|
(make-branch 1
|
|
(make-mobile
|
|
(make-branch 1 10)
|
|
(make-branch 5 2)))))
|
|
|
|
;; Calculations
|
|
;; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
(define (branch-weight branch)
|
|
(let ((structure (branch-structure branch)))
|
|
(if (number? structure)
|
|
structure
|
|
(+ (branch-weight (left-branch structure))
|
|
(branch-weight (right-branch structure))))))
|
|
|
|
(define (total-weight mobile)
|
|
(+ (branch-weight (left-branch mobile))
|
|
(branch-weight (right-branch mobile))))
|
|
|
|
(define (torque branch)
|
|
(* (branch-length branch)
|
|
(branch-weight branch)))
|
|
|
|
(define (balanced? mobile)
|
|
(define (balanced-branch? branch)
|
|
(let ((structure (branch-structure branch)))
|
|
(if (number? structure)
|
|
#t
|
|
(balanced? structure))))
|
|
(let ((left (left-branch mobile))
|
|
(right (right-branch mobile)))
|
|
(and
|
|
(= (torque left)
|
|
(torque right))
|
|
(and (balanced-branch? left)
|
|
(balanced-branch? right)))))
|
|
|
|
;; New representation
|
|
;; ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
(define (make-mobile left right)
|
|
(cons left right))
|
|
|
|
(define (make-branch length structure)
|
|
(cons length structure))
|
|
|
|
(define right-branch cdr)
|
|
(define branch-structure cdr)
|
|
#+end_src
|
|
** Mapping over trees
|
|
*** Exercise 2.30
|
|
Define a procedure `square-tree' analogous to the `square-list'
|
|
procedure of *Note Exercise 2-21::. That is, `square-list' should
|
|
behave as follows:
|
|
|
|
#+begin_src scheme
|
|
(square-tree
|
|
(list 1
|
|
(list 2 (list 3 4) 5)
|
|
(list 6 7)))
|
|
(1 (4 (9 16) 25) (36 49))
|
|
#+end_src
|
|
|
|
Define `square-tree' both directly (i.e., without using any
|
|
higher-order procedures) and also by using `map' and recursion.
|
|
|
|
----------------------------------------------------------------------
|
|
|
|
#+begin_src scheme :tangle yes
|
|
;; -------------------------------------------------------------------
|
|
;; Exercise 2.30
|
|
;; -------------------------------------------------------------------
|
|
|
|
(define (square-tree tree)
|
|
(cond ((null? tree) '())
|
|
((not (pair? tree)) (square tree))
|
|
(else (cons (square-tree (car tree))
|
|
(square-tree (cdr tree))))))
|
|
|
|
(define (square-tree tree)
|
|
(map (lambda (sub-tree)
|
|
(if (pair? sub-tree)
|
|
(square-tree sub-tree)
|
|
(square sub-tree)))
|
|
tree))
|
|
#+end_src
|
|
*** Exercise 2.31
|
|
Abstract your answer to *Note Exercise 2-30:: to produce a
|
|
procedure `tree-map' with the property that `square-tree' could be
|
|
defined as
|
|
|
|
#+begin_src scheme
|
|
(define (square-tree tree) (tree-map square tree))
|
|
#+end_src
|
|
|
|
----------------------------------------------------------------------
|
|
|
|
#+begin_src scheme :tangle yes
|
|
;; -------------------------------------------------------------------
|
|
;; Exercise 2.31
|
|
;; -------------------------------------------------------------------
|
|
|
|
(define (tree-map f tree)
|
|
(map (lambda (sub-tree)
|
|
(if (pair? sub-tree)
|
|
(tree-map f sub-tree)
|
|
(f sub-tree)))
|
|
tree))
|
|
|
|
(define (square-tree tree)
|
|
(tree-map square tree))
|
|
#+end_src
|
|
*** Exercise 2.32
|
|
We can represent a set as a list of distinct elements, and we can
|
|
represent the set of all subsets of the set as a list of lists.
|
|
For example, if the set is `(1 2 3)', then the set of all subsets
|
|
is `(() (3) (2) (2 3) (1) (1 3) (1 2) (1 2 3))'. Complete the
|
|
following definition of a procedure that generates the set of
|
|
subsets of a set and give a clear explanation of why it works:
|
|
|
|
#+begin_src scheme
|
|
(define (subsets s)
|
|
(if (null? s)
|
|
(list nil)
|
|
(let ((rest (subsets (cdr s))))
|
|
(append rest (map <??> rest)))))
|
|
#+end_src
|
|
|
|
----------------------------------------------------------------------
|
|
|
|
#+begin_src scheme :tangle yes
|
|
(define (subsets s)
|
|
(if (null? s)
|
|
(list '())
|
|
(let ((rest (subsets (cdr s))))
|
|
(append rest (map (lambda (x) (cons (car s) x)) rest)))))
|
|
#+end_src
|
|
* Sequences as Conventional Interfaces
|
|
** Sequence Operations
|
|
#+begin_src scheme :tangle yes
|
|
;; ===================================================================
|
|
;; Section 2.2.3: Sequences as Conventional Interfaces
|
|
;; ===================================================================
|
|
(define (filter predicate sequence)
|
|
(cond ((null? sequence) nil)
|
|
((predicate (car sequence))
|
|
(cons (car sequence)
|
|
(filter predicate (cdr sequence))))
|
|
(else (filter predicate (cdr sequence)))))
|
|
|
|
(define (accumulate op initial sequence)
|
|
(if (null? sequence)
|
|
initial
|
|
(op (car sequence)
|
|
(accumulate op initial (cdr sequence)))))
|
|
|
|
#+end_src
|
|
*** Exercise 2.33
|
|
Fill in the missing expressions to complete the
|
|
following definitions of some basic list-manipulation operations
|
|
as accumulations:
|
|
|
|
#+begin_src scheme
|
|
(define (map p sequence)
|
|
(accumulate (lambda (x y) <??>) nil sequence))
|
|
|
|
(define (append seq1 seq2)
|
|
(accumulate cons <??> <??>))
|
|
|
|
(define (length sequence)
|
|
(accumulate <??> 0 sequence))
|
|
#+end_src
|
|
|
|
----------------------------------------------------------------------
|
|
|
|
#+begin_src scheme :tangle yes
|
|
;; -------------------------------------------------------------------
|
|
;; Exercise 2.33
|
|
;; -------------------------------------------------------------------
|
|
|
|
(define (map p sequence)
|
|
(accumulate (lambda (x y) (cons (p x) y)) '() sequence))
|
|
|
|
(define (append seq1 seq2)
|
|
(accumulate cons seq2 seq1))
|
|
|
|
(define (length sequence)
|
|
(accumulate (lambda (e acc) (+ 1 acc)) 0 sequence))
|
|
#+end_src
|
|
|
|
*** Exercise 2.34
|
|
Evaluating a polynomial in x at a given value of
|
|
x can be formulated as an accumulation. We evaluate the polynomial
|
|
|
|
#+begin_example
|
|
a_n r^n | a_(n-1) r^(n-1) + ... + a_1 r + a_0
|
|
#+end_example
|
|
|
|
using a well-known algorithm called "Horner's rule", which
|
|
structures the computation as
|
|
|
|
#+begin_example
|
|
(... (a_n r + a_(n-1)) r + ... + a_1) r + a_0
|
|
#+end_example
|
|
|
|
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.(3)
|
|
|
|
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.
|
|
|
|
#+begin_src scheme
|
|
(define (horner-eval x coefficient-sequence)
|
|
(accumulate (lambda (this-coeff higher-terms) <??>)
|
|
0
|
|
coefficient-sequence))
|
|
#+end_src
|
|
|
|
For example, to compute 1 + 3x + 5x^3 + x^(5) at x = 2 you would
|
|
evaluate
|
|
|
|
#+begin_src scheme
|
|
(horner-eval 2 (list 1 3 0 5 0 1))
|
|
#+end_src
|
|
|
|
----------------------------------------------------------------------
|
|
|
|
#+begin_src scheme :tangle yes
|
|
;; -------------------------------------------------------------------
|
|
;; Exercise 2.34
|
|
;; -------------------------------------------------------------------
|
|
|
|
(define (horner-eval x coefficient-sequence)
|
|
(accumulate (lambda (this-coeff higher-terms)
|
|
(+ this-coeff (* higher-terms x)))
|
|
0
|
|
coefficient-sequence))
|
|
#+end_src
|
|
|
|
*** Exercise 2.35
|
|
Redefine `count-leaves' from section *Note 2-2-2:: as an
|
|
accumulation:
|
|
|
|
#+begin_src scheme
|
|
(define (count-leaves t)
|
|
(accumulate <??> <??> (map <??> <??>)))
|
|
#+end_src
|
|
|
|
----------------------------------------------------------------------
|
|
|
|
#+begin_src scheme :tangle yes
|
|
;; -------------------------------------------------------------------
|
|
;; Exercise 2.35
|
|
;; -------------------------------------------------------------------
|
|
|
|
(define (count-leaves t)
|
|
(accumulate + 0 (map
|
|
(lambda (node)
|
|
(if (pair? node)
|
|
(count-leaves node)
|
|
1))
|
|
t)))
|
|
#+end_src
|
|
|
|
*** 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 `s' is a sequence containing four sequences, `((1
|
|
2 3) (4 5 6) (7 8 9) (10 11 12)),' then the value of
|
|
`(accumulate-n + 0 s)' should be the sequence `(22 26 30)'. Fill
|
|
in the missing expressions in the following definition of
|
|
`accumulate-n':
|
|
|
|
#+begin_src scheme
|
|
(define (accumulate-n op init seqs)
|
|
(if (null? (car seqs))
|
|
nil
|
|
(cons (accumulate op init <??>)
|
|
(accumulate-n op init <??>))))
|
|
#+end_src
|
|
|
|
----------------------------------------------------------------------
|
|
|
|
#+begin_src scheme :tangle yes
|
|
;; -------------------------------------------------------------------
|
|
;; Exercise 2.36
|
|
;; -------------------------------------------------------------------
|
|
|
|
(define (accumulate-n op init seqs)
|
|
(if (null? (car seqs))
|
|
'()
|
|
(cons (accumulate op init (map car seqs))
|
|
(accumulate-n op init (map cdr seqs)))))
|
|
#+end_src
|
|
|
|
** Exercise 2.37
|
|
Suppose we represent vectors v = (v_i) as sequences of numbers, and
|
|
matrices m = (m_(ij)) as sequences of vectors (the rows of the matrix).
|
|
For example, the matrix
|
|
|
|
#+begin_example
|
|
+- -+
|
|
| 1 2 3 4 |
|
|
| 4 5 6 6 |
|
|
| 6 7 8 9 |
|
|
+- -+
|
|
#+end_example
|
|
|
|
is represented as the sequence `((1 2 3 4) (4 5 6 6) (6 7 8 9))'. With
|
|
this representation, we can use sequence operations to concisely
|
|
express the basic matrix and vector operations. These operations
|
|
(which are described in any book on matrix algebra) are the following:
|
|
|
|
#+begin_example
|
|
__
|
|
(dot-product v w) returns the sum >_i v_i w_i
|
|
|
|
(matrix-*-vector m v) returns the vector t,
|
|
__
|
|
where t_i = >_j m_(ij) v_j
|
|
|
|
(matrix-*-matrix m n) returns the matrix p,
|
|
__
|
|
where p_(ij) = >_k m_(ik) n_(kj)
|
|
|
|
(transpose m) returns the matrix n,
|
|
where n_(ij) = m_(ji)
|
|
#+end_example
|
|
|
|
We can define the dot product as(4)
|
|
|
|
#+begin_src scheme
|
|
(define (dot-product v w)
|
|
(accumulate + 0 (map * v w)))
|
|
#+end_src
|
|
|
|
Fill in the missing expressions in the following procedures for
|
|
computing the other matrix operations. (The procedure `accumulate-n'
|
|
is defined in *Note Exercise 2-36::.)
|
|
|
|
#+begin_src scheme
|
|
(define (matrix-*-vector m v)
|
|
(map <??> m))
|
|
|
|
(define (transpose mat)
|
|
(accumulate-n <??> <??> mat))
|
|
|
|
(define (matrix-*-matrix m n)
|
|
(let ((cols (transpose n)))
|
|
(map <??> m)))
|
|
#+end_src
|
|
*** Exercise 2.38
|
|
The `accumulate' procedure is also known as `fold-right', because
|
|
it combines the first element of the sequence with the result of
|
|
combining all the elements to the right. There is also a
|
|
`fold-left', which is similar to `fold-right', except that it
|
|
combines elements working in the opposite direction:
|
|
|
|
#+begin_src scheme
|
|
(define (fold-left op initial sequence)
|
|
(define (iter result rest)
|
|
(if (null? rest)
|
|
result
|
|
(iter (op result (car rest))
|
|
(cdr rest))))
|
|
(iter initial sequence))
|
|
#+end_src
|
|
|
|
What are the values of
|
|
|
|
(fold-right / 1 (list 1 2 3))
|
|
|
|
(fold-left / 1 (list 1 2 3))
|
|
|
|
(fold-right list nil (list 1 2 3))
|
|
|
|
(fold-left list nil (list 1 2 3))
|
|
|
|
Give a property that `op' should satisfy to guarantee that
|
|
`fold-right' and `fold-left' will produce the same values for any
|
|
sequence.
|
|
|
|
----------------------------------------------------------------------
|
|
|
|
#+begin_src scheme
|
|
;; -------------------------------------------------------------------
|
|
;; Exercise 2.38
|
|
;; -------------------------------------------------------------------
|
|
|
|
(define fold-right accumulate)
|
|
|
|
(define (fold-left op initial sequence)
|
|
(define (iter result rest)
|
|
(if (null? rest)
|
|
result
|
|
(iter (op result (car rest))
|
|
(cdr rest))))
|
|
(iter initial sequence))
|
|
|
|
;; (fold-right / 1 (list 1 2 3))
|
|
;; 3/2
|
|
|
|
;; (fold-left / 1 (list 1 2 3))
|
|
;; 1/6
|
|
|
|
;; (fold-right list nil (list 1 2 3))
|
|
;; (((() 1) 2) 3)
|
|
|
|
;; (fold-left list nil (list 1 2 3))
|
|
;; (1 (2 (3 ())))
|
|
#+end_src
|
|
|
|
*** Exercise 2.39
|
|
Complete the following definitions of `reverse'
|
|
(*Note Exercise 2-18::) in terms of `fold-right' and `fold-left'
|
|
from *Note Exercise 2-38:::
|
|
|
|
#+begin_src scheme
|
|
(define (reverse sequence)
|
|
(fold-right (lambda (x y) <??>) nil sequence))
|
|
|
|
(define (reverse sequence)
|
|
(fold-left (lambda (x y) <??>) nil sequence))
|
|
#+end_src
|
|
|
|
----------------------------------------------------------------------
|
|
|
|
#+begin_src scheme :tangle yes
|
|
;; -------------------------------------------------------------------
|
|
;; Exercise 2.39
|
|
;; -------------------------------------------------------------------
|
|
|
|
(define (reverse sequence)
|
|
(fold-right (lambda (x y) (append y (list x))) '() sequence))
|
|
|
|
(define (reverse sequence)
|
|
(fold-left (lambda (x y) (cons y x)) '() sequence))
|
|
#+end_src
|