1) Implement the macros mentioned in Slide 25 of the lesson.

2) Implement a correct version of our-dotimes.

3) A typical way to use files is to first open them, read/write some data and finally close them. The naive way is to do the following:

(let ((file (open #P"some filename")))
   (... file ...)
   (close file))

However, this code is not robust because before calling the close function, an exception might be thrown. Common Lisp provides unwind-protect for ensuring that code is executed no matter what happens.

Implement a with-file macro that uses unwind-protect to ensure that a file is always closed after some block of code. (It should be be named with-open-file, but this is already a standard macro in Common Lisp.)

4) Common Lisp provides several constructs for executing sequences of forms. progn executes forms and returns the value of the last form, prog1 executes forms and returns the value of the first form, prog2 execute forms and returns the value of the second form. For example:

(let ((x 0))
   (progn
      (setq x 1)
      (setq x 2)
      x)) => 2

(let ((x 0))
   (prog1
      x
      (setq x 1)
      x)) => 0

(let ((x 0))
   (prog2
      (setq x 1)
      x
      (setq x 2)
      x)) => 1

Write a macro prog-mark that allows you to return an arbitrary value from a block of code by marking it. For example:

(prog-mark
   1 2 (mark 3) 4 5) => 3

(prog-mark
   1 2 (+ 3 4 (mark 5) 6 7) 8 9) => 5

5) Common Lisp doesn't provide Scheme's delay and force. Implement them. See the Scheme specification at http://www.schemers.org/Documents/Standards/R5RS/HTML/ for a specification of delay and force. Which of the extensions discussed for force in the Scheme standard cannot be implemented with macros?

6) Write a macro 'trace that arranges for the passed expression to be printed and evaluated. For example:

(trace (+ 3 4)) prints "(+ 3 4) = 7" and returns 7
(* 2 (trace (+ 4 5))) prints "(+ 4 5) = 9" and returns 18

Note that (macroexpand '(trace (+ 3 4))) should just return code and not print anything.

7) When writing macros that avoid variable capture, one tends to use generated symbols a lot. Write a macro 'with-gensyms that automates this. For example:

(with-gensyms (a)
   ...)

...should expand into...

(let ((a (gensym)))
  ...)

What can you do so that the generated symbol has a name that is helpful during debugging? Consider that with-gensyms is typically used in macros like this:

(defmacro m (...)
   (with-gensyms (...)
      `( ... )))

8) See http://en.wikipedia.org/wiki/Newton's_method for an explanation of Newton's method for finding the roots of a function. Assume, it is implemented as a function 'newton that takes two arguments, the function for which to find the roots and the first derivative of that function. So for example, (newton (lambda (x) (* 4 x)) (lambda (x) 4)) would return the root for y = 4*x, and (newton (function sin) (function cos)) would return a root for the function "sin".

We don't want to determine the first derivative of a function by hand. Write a macro 'roots that automates this. So for example (roots (lambda (x) (* 4 x))) would expand into (newton (lambda (x) (* 4 x)) (lambda (x) 4)) and (roots (function sin)) would expand into (newton (function cos)).

Start with writing a simple version, and test it by using macroexpand. Then consider extending it with error checking, so that a programmer knows at compile-time whether the passed function can be correctly expanded, and with simplification step so that the program doesn't need to do unnecessary computations at runtime.