Just a quick note about a pet-peeve of mine regarding define-macro:
The disadvantages of define-macro:
- with define-macro you have to care about hygiene yourself (e.g. you
have to use (gensym) to introduce new identifyers into the transformed code, and you have to fully qualify symbols that you want to refer to a particular package instead of to the identifyers in the package of the user of the macro)
It's worse than this. Consider the following example:
(define-macro (do-times i-and-n . body) (let ((i (car i-and-n)) (nn (cdr i-and-n)) (n (gensym))) `(let ((,n ,nn)) (do ((,i 0 (+ ,i 1))) ((= ,i ,n)) ,@body))))
(define v (vector 1 2 3 4 5 6 7 8 9 10)) (define v-of-v (vector v v v v v v v v v))
;; This works (do-times (i 10) (if (not (= (vector-ref v i) (+ i 1))) (display "not equal") (display "equal")) (newline))
;; This barfs, because we've *locally* bound "=" (pretend we've suitably defined vector=) ;; The error will be something like "vector=: expected <vector> got 1", coming from ;; the use of '= in the do test the macro expands into. (let ((= vector=)) (do-times (i 10) (if (not (= (vector-ref v-of-v i) v)) (display "not equal") (display "equal")) (newline)))
I've been bit by this bug before myself, in real code. And *there's nothing you can do about it* using define-macro. It's *far* worse than having to define a new gensym each time you want to introduce a local variable. If you want to use define-macro, *don't ever* re-define *any* standard symbol (even locally) if you want to be sure that you're not hosing macros. Syntax-case/rules just does the right thing here---and saves you from a very hard-to-find class of bugs.
Will