diff --git a/2-2.org b/2-2.org new file mode 100644 index 0000000..c07f7c0 --- /dev/null +++ b/2-2.org @@ -0,0 +1,686 @@ +#+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) ) + #+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) ) + #+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