Variable Capture

Start with a macro:

(defmacro ntimes (n &rest body)
	`(do ((x 0) (+ x 1)))
		((>= x ,n))
	    ,@body))

One problem here is variable capture -- the variable x could appear in the context in which the macro is expanded causing a name collision. We can use gensym() to fix this as follows:

(defmacro ntimes (n &rest body)
  (let ((g (gensym)))
	`(do ((,g 0) (+ ,g 1)))
		((>= ,g ,n))
	    ,@body))

In this second version, we use a let to bind a gensym'd variable name to g, and then use the comma (,) to force g to be evaluated as the macro is expanded.

The Multiple Evaluation Problem

Start with a different macro this time:

(defmacro for ((var start stop) &body body)
	`(do ((,var ,start (1+ ,var)))
		 ((> ,var ,stop))
	    ,@body))

As mentioned in class, this evaluates the stop expression on each pass through the do loop, which is especially bad if the stop expression has side effects. To fix this, move the stop expression evaluation outside the loop, as follows:

(defmacro for ((var start stop) &body body)
  (let ((gstop (gensym)))
	`(do  ((,var ,start (1+ ,var)))
           (,gstop ,stop))
        ((> ,var ,stop))
		,@body))

By the way, did you notice that there's still a problem with our revised ntimes macro?