Programming Assignment #3

Last modified: "September 19, 1997 15:03:59 by matt"

From Graham's ANSI Common Lisp: Ch 9: 2,5; Ch. 10: 1, 3, 4, 6
9.2 Define a function that takes an integer number of cents and returns four values (can be a list) showing how to make that number out of 25-, 10-, 5-, and 1-cent pieces, using the smallest total number of coins.

9.5 Suppose f is a function of one (real) argument, and that min and max are nonzero reals such that f has a root (returns zero) for one argument i such that min<i<max, and f(min) and f(max) have different signs. Define a function, findRoot, that takes four argument, f, min, max, and epsilon, and returns an approximation of i accurate to within plus or minus that value of epsilon.

For example,

> (findRoot #'(lambda (z) (- (* z z) 9.0)) -2.0 5.0 .01)

Should return a number between 2.99 and 3.01, as the given function (here, a lambda expression) has a root at 3.00.

10.1 If x is a, y is b, and z is (c d), write backquoted expressions containing only variables that yield each of the following:

  1. ((c d) a z)
  2. (x b c d)
  3. ((c d a) z)

10.3 Define a macro, nth-expr, that takes a number n followed by one or more expressions, and returns that value of the nth expression:

> (let ((n 2))
     (nth-expr n (/ 1 0) (+ 1 2) (/ 1 3)))
3 

Note: The book does not explain very well when macro expansion actually occurs, which is at compile-time, which precedes execution-time. This means that nth-expr cannot access the value of the variable n during macro expansion, because n has no value until execution-time.

Recall the read-eval-print loop. The evaluation of the let expression above would occur something like this: the reader receives the let s-expression and attempts to parse it. It detects that one of the symbols, nth-exp, references a macro. The macro is executed, resulting in a piece of code, which effectively takes the place of the nth-exp s-expression. The resulting s-expression would look something like:

(let ((n 2)) <result of macro expansion>)

This completes the reader's work, and this s-expression is passed on to the evaluator. The evaluator sees the let and instantiates the variable n on the program stack, giving it a value of 2. Only now can the value of n be referenced (i.e., can n be evaluated). In particular, <result of macro expansion> could contain references to n.

10.4 Define ntimes (page 167) to expand into a (local) recursive function instead of a do.

Note: the macro is not itself recursive, just the code that it expands into. You'll want to look into the use of either flet or labels.

10.6 Define a macro, protect, that takes a list of variables and a body of code, and ensures that the variables revert to their original values after the body of code is evaluated.

For example,

(let ((x 3))
  (protect (x)
    (setq x (* x 2))
    (format t "Doubled value of x is ~d~%" x))
  (format t "Value of x is ~d~%" x))

Should print out "Doubled value of x is 6" and then "Value of x is 3".