Concrete Abstractions: Chapter 7

Exercise 7.5 Generalize sum to a higher-order procedure that can accumulate together the elements of a list in an arbitrary fashion by using a combining procedure (such as +) specified by a procedural parameter. When the list is empty, sum returned 0, but this result isn’t appropriate for other combining procedures. For example, if the com- bining procedure is *, 1 would be the appropriate value for an empty list. (Why?) Following are two possible approaches to this problem:
a. Write the higher-order procedure so that it only works for nonempty lists. That way, the base case can be for one-element lists, in which case the one element can be returned.
b. Write the higher-order procedure so that it takes an additional argument, beyond the list and the combining procedure, that specifies the value to return for an empty list.


; b.

Exercise 7.6 a. Write a procedure that will count the number of times a particular element occurs in a given list.
b. Generalize this procedure to one that will count the number of elements in a given list that satisfy a given predicate.


Exercise 7.13: The procedure map is extraordinarily handy for creating lists of all sorts. Each of the following problems can be solved by using map.
a. Write a procedure that, when given a positive integer n, returns a list of the first n perfect squares.
b. Write a procedure that, when given a positive integer n, returns a list of the first n even integers.
c. Write a procedure called sevens that, when given a positive integer n, returns a list of n sevens. For example:

d. Write a procedure that, when given a list of positive integers, returns a list of lists of integers. Each of these lists should be the positive integers from 1 to whatever was in the original list. For example,





Ex 7.14

Exercise 7.42: Write a procedure called apply-all that, when given a list of functions and a number, will produce the list of the values of the functions when applied to the number.


Exercise 7.44: Consider the following two procedures. The procedure last selects the last element from a list, which must be nonempty. It uses length to find the length of the list.

a. How many cdrs does (length lst) do when lst has n elements?
b. How many calls to length does (last lst) make when lst has n elements?
c. Express in Theta notation the total number of cdrs done by (last lst), including cdrs done by length, again assuming that lst has n elements.
d. Give an exact formula for the total number of cdrs done by (last lst), including cdrs done by length, again assuming that lst has n elements.

a. n, which can be easily seen. An empty list needs 0 cdrs, a list with length 1 needs one cdrs. If we use induction, we can assume that this holds. For a list of length (n+1), we can see that length uses one cdr and then generates (length ). Therefore there are n uses of cdr for a list of length n.
b. Let’s start with the base case. (last ‘(1)) here last calls length one time. We can see that each time last have to call length. Therefore we can see that it needs n calls for a list of length n. The idea of the proof follows the last one.
c. and d. How many cdrs does last need without considering length? If the length is 1, it needs 0. If the length is 2, it needs 1. In general it needs (n-1) times cdr. We already know how often last calls length, so we can calculate the number of all calls. There are (n-1) calls from last directly. For each iteration in last we need 1 call of length. And each call of length needs (k+1) cdrs. If we merge everything together, we get the following table

Now we just have to add cdr from last and cdr from length and get:
(n-1) + sum_{i=1}{n} i = (n-1) + frac{n(n-1)}{2} = frac{n^2 + 3n - 2}{2}
Which is Theta(n^2) in Theta notation.

Exercise 7.47: Write a procedure map-2 that takes a procedure and two lists as arguments and returns the list obtained by mapping the procedure over the two lists, drawing the two arguments from the two lists. Write this procedure map-2. You may assume that the lists have the same length.


Concrete Abstractions: Chapter 6

Exercise 6.23
A three-dimensional (3D) vector has x, y, and z coordinates, which are numbers. 3D vectors can be constructed and accessed using the following abstract interface:

(make-3D-vector x y z)
(x-coord vector)
(y-coord vector)
(z-coord vector)

a. Using this abstract interface, define procedures for adding two vectors, finding the dot-product of two vectors, and scaling a vector by a numerical scaling factor.
b. Choose a representation for vectors and implement make-3D-vector, x-coord, y-coord, and z-coord.

Solution: a.


This was a quite short chapter. However chapter 7 is rather long. This exercise above covers pretty much the whole chapter, it was just about cons, car and cdr.

Concrete Abstractions: Chapter 5

Exercise 5.6 Write a general purpose procedure, that when given two integers, low and high, and a procedure for computing a function f , will compute f(text{low}) + f(text{low} + 1) + f (text{low} + 2) + ... + f (text{high}). Show how it can be used to sum the squares of the integers from 5 to 10 and to sum the square roots of the integers from 10 to 100.

Solution: I wrote a iterative version of it because you have to directly apply the function to each number, i.e. it isn’t commutative.

Exercise 5.11 Write a procedure make-verifier, which takes f and m as its two arguments and returns a procedure capable of checking a number. The argument f is itself a procedure, of course. Here is a particularly simple example of a verifier being made and used:

The value #t is the “true” value; it indicates that the number is a valid ISBN.
As we just saw, for ISBN numbers the divisor is 11 and the function is simply f(i, d_i ) = i * di. Other kinds of numbers use slightly more complicated functions, but you will still be able to use make-verifier to make a verifier much more easily than if you had to start from scratch.


Exercise 5.12 For UPC codes (the barcodes on grocery items), the divisor is 10, and the function f (i, d_i ) is equal to d_i itself when i is odd, but to 3d_i when i is even. Build a verifier for UPC codes using make-verifier, and test it on some of your groceries. (The UPC number consists of all the digits: the one to the left of the bars, the ones underneath the bars, and the one on the right.) Try making some mistakes, like switching or changing digits. Does your verifier catch them?

Solution: Yeah, the mistakes were caught. By the way you can see here how powerful high-order functions are.

Exercise 5.13 Credit card numbers also use a divisor of 10 and also use a function that yields d_i itself when i is odd. However, when i is even, the function is a bit fancier: It is 2d_i if $latex d_i < 5$, and $latex 2d_i + 1$ if $latex d_i geq 5.$ Build a verifier for credit card numbers. In the dialog at the beginning of this section, did the order taker really mistype the number, or did the customer read it incorrectly? Solution: The credit card number was correct.

Exercise 5.13 The serial number on U.S. postal money orders is self-verifying with a divisor of 9 and a very simple function: f (i, d_i ) = di, with only one exception, namely, f (1, d_1 ) = -d_1. Build a verifier for these numbers, and find out which of these two money orders is mistyped: 48077469777 or 48077462766.
Actually, both of those money order numbers were mistyped. In one case the error was that a 0 was replaced by a 7, and in the other case two digits were reversed. Can you figure out which kind of error got caught and which didn’t? Does this help explain why the other kinds of numbers use fancier functions?

Solution: The reversal of digits, if the digit isn’t the first one, isn’t caught by this verification function. This is a reason for using fancier verification functions.

Exercise 5.17 Suppose you have a function and you want to find at what integer point in a given range it has the smallest value. For example, looking at the following graph of the function f (x) = x^2 - 2x, you can see that in the range from 0 to 4, this function has the smallest value at 1. We could write a procedure for answering questions like this; it could be used as follows for this example:

Here is the procedure that does this; fill in the two blanks to complete it:

Solution: I find it actually pretty hard to do fill in questions. Anyhow, here’s the solution:

Exercise 5.18 Consider the following definitions:

For the following questions, be sure to indicate how you arrived at your answer:
a. What is the value of (mystery 4)?
b. What is the value of the procedural call ((make-scaled 2 (make-scaled 3 add-one)) 4)?

Solution: a. You can see that mystery gets a function from (make-scaled 3 add-one). This produces (lambda(x) (* 3 (add-one x))) which equals (lambda(x) (* 3 (+ 1 x))). Therefore the value is 15.
b. Let’s take this call apart. (make-scaled 2 f) produces (lambda(x) (* 2 (f x)). Here f is (make-scaled 3 add-one) which produces the known (lambda(x) (* 3 (+ 1 x))) = 15 for x = 4. If you substitute this into (make-scaled 2 f) it becomes (lambda (x) (* 2 15)) = 30.

Exercise 5.20 Suppose the following have been defined:

For each of the following expressions, indicate whether an error would be signaled, the value would be a procedure, or the value would be a number. If an error is signaled, explain briefly the nature of the error. If the value is a procedure, specify how many arguments the procedure expects. If the value is a number, specify which number.
a. f
b. g
c. (* (f 3 2) 7)
d. (g 6)
e. (f 6)
f. ((f 4 7) 5)

a. f is a procedure with two arguments.
b. g is a procedure returned by f with one argument.
c. (* (f 3 2) 7) evals to (* (lambda (x) (+ (* 3 x) 2) 7) = (* 23) which throws an error because * needs at least two arguments.
d. Here we got another value: (g 6) = ((f 3 2) 6) = (+ (* 3 6) 2) which equals 20.
e. f needs two arguments. So this throws an error.
f. (+ (* 4 5) 7) which equals 27.

Exercise 5.24 Consider the following procedure:

a. Write a mathematical formula involving n that tells how many times this procedure uses the procedure it is given as its second argument. Justify your answer.
b. Give a simple Theta order of growth for the quantity you determined in part a. Justify your answer.
c. Suppose you were to rewrite this procedure to make it more efficient. What (in terms of n) is the minimum number of times it can invoke f and still always determine the correct answer? Justify your answer. (You are not being asked to actually rewrite the procedure.)

Solution: a. If next > n then loop returns directly smallest-so-far, so there’s no call of f. If next <= n then there are two calls in the if header. Therefore there are 2(n-1) function calls of f.
b. We can see that 2(n-1) = 2n - 2. 2n is the biggest term and 2 is just a factor, therefore \Theta(n).
c. We can save (f where-smallest-so-far) by adding it in the parameter list of loop. In the ideal case we just need to calculate (f where-smallest-so-far) one time and (f next-to-try) (n – 1) times. However, in the worst case there’s no improvement.

Concrete Abstractions: Chapter 4

Exercise 4.2 In this exercise you will show that this version of mod-expt does \Theta (e) multiplications, as we claimed.
a. Use induction to prove each of the following about this latest version of mod-expt:
(1) e is a nonnegative integer, (mod-expt b e m) does at least e multiplications.
(2) When e is a positive integer, (mod-expt b e m) does at most 2e – 1 multiplications.

Solution: At first I wrote the function mathematically. mod^* = m^*(x, y) = xy \text{ mod } m.
\text{mod-expt} = m(b, e, m)
m(b, 0, m) = 1
m(b, e, m) = \begin{cases} m^*(m(b, e/2, m), m(b, e/2, m) & \text{ if e is even}\\ m^*(m(b, e-1, m), b) & \text{ if e is odd }\\ \end{cases}

(1) Ok, now let’s start with the first assumption: m(b, e, m) does at least e multiplications. For e=0 follows that m(b, 0, m) = 1. So that’s true. Therefore we can assume that this holds to e+1.
If e+1 is odd:
m(b, e+1, m) = m^*(m(b, e, m), b), we assumed that m(b, e, m) does e multiplications. If we look back at the definition of m^*(x,y), we can see that there’s one multiplication. Therefore there are e + 1 multiplications. That was the best case, let’s look at the worst one.

(2) The assumption is that m(b, e, m) needs 2e-1 multiplications at most. Let’s check the base case for e=1. m(b, 1, m) = m^*(m(b, 0, m), b). Here we get one multiplication from m^*, so the maximum limit holds. If e+1 is even, it follows that:
m(b, e+1, m) = m^*(m(b, (e+1)/2, m), m(b, (e+1)/2, m)). Each nested m(b, (e+1)/2, m) needs at most 2* \frac{(e+1)}{2} -1 multiplications and we got another from m^*. That is, there are 2 * (2*\frac{(e+1)}{2} -1) + 1 = 2(e+1) - 1 multiplications.

You can check the even case in (1) and the odd case in (2) for yourself and see that these are bigger and respectively smaller than the other ones.

Exercise 4.11 Consider the following procedures:

In answering the following, assume that n is a nonnegative integer. Also, justify your answers.
a. Give a formula for how many multiplications the procedure factorial does as a function of its argument n.
b. Give a formula for how many multiplications the procedure factorial-sum1 does (implicitly through factorial) as a function of its argument n.
c. Give a formula for how many multiplications the procedure factorial-sum2 does as a function of its argument n.

a. \text{factorial}(0) = 1, \text{factorial}(n) = n * \text{factorial}(n-1)
What happens for n = 1, 2, 3,..? Let’s see:
\text{factorial}(1) = 1 * \text{factorial}(0) = 1 * 1
\text{factorial}(2) = 2 * \text{factorial}(1) = 2 * 1 * \text{factorial}(0) = 2 * 1 * 1
\text{factorial}(3) = 3 * \text{factorial}(2) = 3 * 2 * \text{factorial}(1)
= 3 * 2 * 1 * \text{factorial}(0) = 3 * 2 * 1 * 1
We can see that there are probably n+1 multiplications. We can prove that by induction.
\text{factorial}(n+1) = (n+1) * \text{factorial}(n). We assumed that \text{factorial}(n) multiplies (n+1) times. Therefore we have 1 + (n+1) = (n+1) + 1 multiplications.
b. And again written mathematically:
\text{factorial-sum1}(0) = 0
\text{factorial-sum1}(n) = \text{factorial}(n) + \text{factorial-sum1}(n-1)
So was happens here here for n = 1, 2, ..?
\text{factorial-sum1}(1) = \text{factorial}(1) + \text{factorial-sum1}(0)
= (1 * 1) + 0
\text{factorial-sum1}(2) = \text{factorial}(2) + \text{factorial-sum1}(1)
= (2 * 1 * 1) + \text{factorial}(1) + \text{factorial-sum1}(0)
= (2 * 1 * 1) + (1 * 1) + 0
For n=1 we need 2 multiplications, for n=2 we need 2 + 3 multiplications. In general we need \sum_{i=1}^n (i+1) multiplications. This can be simplified: \sum_{i=1}^n i + sum_{i=1}^n 1 = \frac{n(n+1)}{2} + n = \frac{n^2 + 3n}{2}.
c. This is pretty straight forward. You can see that each iteration k is increased by one. It starts at k = 1 and stops if k > n. So it runs n times.

Exercise 4.12 How many ways are there to factor n into two or more numbers (each of which must be no smaller than 2)? We could generalize this to the problem of finding how many ways there are to factor n into two or more numbers, each of which is no smaller than m. That is, we write

Your job is to write ways-to-factor-using-no-smaller-than.

Solution: An easy way to find factors is just to try every number if it divides n, starting with m. If a number divides n, take the division and find its factors.

Exercise 4.13 Consider the following procedure:

How many multiplications (expressed in \Theta notation) will the computation of (bar n) do? Justify your answer. You may assume that n is a nonnegative integer.

Solution: The definition of bar is:
\text{bar}(0) = 5
\text{bar}(1) = 7
\text{bar}(n) = n*\text{n-2}
For n = 0, 1, 2, 3, ... we get:
\text{bar}(0) = 5 \text{ | (0 multiplications)}
\text{bar}(1) = 7 \text{ | (0 multiplications)}
\text{bar}(2) = 2 * \text{bar}(0) = 2 * 5 \text{ | (1 multiplications)}
\text{bar}(3) = 3 * \text{bar}(1) = 3 * 7 \text{ | (1 multiplications)}
\text{bar}(4) = 4 * \text{bar}(2) = 4 * 2 * 5 \text{ | (2 multiplications)}
\text{bar}(5) = 5 * \text{bar}(3) = 5 * 3 * 7 \text{ | (2 multiplications)}
You can see that there are between \frac{n-1}{2} and \frac{n}{2} multiplications. Therefore there are \Theta(n) multiplications at general.

Exercise 4.14 Consider the following procedures:

How many multiplications (expressed in \Theta notation) will the computation of (foo n) do? Justify your answer.

Solution: It’s basically the same schema as the other exercises. If we look at foo it looks like this:
\text{foo}(n) = \text{fac}(n) + \text{bar}(n, n) We already know that \text{fac}(n) needs (n+1) multiplications. If we look at bar, we can see how it works.
\text{bar}(i,j) = \text{fac}(i) * \text{bar}(i,j-1) we can simplify this because foo which calls bar only uses the argument n.
\text{bar}(n,n) = \text{fac}(n) * \text{bar}(n,n-1). Because we already know how many multiplications fac needs, we can concentrate on bar. Let’s see what it does for n = 1, 2, 3, ...:
\text{bar}(0, 0) = 1 \text{ | 0 multipl. }
\text{bar}(1, 1) = \text{fac}(1) * \text{bar}(0, 0) text { | 2 + 1 + 0 multipl.}
\text{bar}(2, 2) = \text{fac}(2) * \text{bar}(1, 1) \text { | 3 + 1 + (2 + 1) multipl.}
We can generalize this as \sum_{k=3}^{n+2} k = \sum_{k=1}^{n+2} - 3 which can be simplified as: \frac{(n+2)(n+3)}{2} - 3 = \frac{(n+2)(n+3) - 6}{2} = \frac{n^2 + 5n}{2} therefore we have \Theta(n^2) multiplications.

Exercise 4.17 Consider the following enumeration problem: How many ways can you choose k objects from n distinct objects, assuming of course that 0 \leq k \leq n? For example, how many different three-topping pizzas can be made if you have six toppings to choose from?
The number that is the answer to the problem is commonly written as C(n, k). Here is an algorithm for computing C(n, k): […]
Using this algorithm, write a tree-recursive procedure that calculates the numbers C(n, k) described above.


Exercise 4.18 One way to sum the integers from a up to b is to divide the interval in half, recursively sum the two halves, and then add the two sums together. Of course, it may not be possible to divide the interval exactly in half if there are an odd number of integers in the interval. In this case, the interval can be divided as nearly in half as possible.
a. Write a procedure implementing this idea.
b. Let’s use n as a name for the number of integers in the range from a up to b. What is the order of growth (in \Theta notation) of the number of additions your procedure does, as a function of n? Justify your answer.

Solution: a.

b. It’s basically the same as in mod-expt because both split up the calculation in two branches each time. Therefore it needs \Theta(\text{log } n) additions.