Hygienic vs Unhygienic Macros

defmacro (CL, Clojure, Elisp) Simple, full power (intentional capture: anaphoric macros like aif with it) Must manage capture manually syntax-rules (Scheme) Hygienic, declarative patterns Limited (no arbitrary computation)

syntax-case / syntax-parse (R6RS, Racket) Hygienic and fully programmable, great error messages

;; Unhygienic: variable capture bug (Common Lisp)
(defmacro bad-swap (a b)
  `(let ((tmp ,a)) (setf ,a ,b) (setf ,b tmp)))
(let ((tmp 1) (other 2))
  (bad-swap tmp other)                   ; breaks: the macro's tmp shadows the user's tmp
  (list tmp other))                      ; (1 2) instead of (2 1)

;; Fixed with gensym
(defmacro good-swap (a b)
  (let ((tmp (gensym "TMP")))
    `(let ((,tmp ,a)) (setf ,a ,b) (setf ,b ,tmp))))
;; Idiomatic CL: (rotatef a b)
;; Hygienic by default (Scheme): this just works
(define-syntax swap!
  (syntax-rules ()
    ((_ a b) (let ((tmp a)) (set! a b) (set! b tmp)))))
(let ((tmp 1) (other 2))
  (swap! tmp other)
  (list tmp other))                      ; (2 1)
;; Intentional capture: anaphoric if (Common Lisp, from "On Lisp")
(defmacro aif (test then &optional else)
  `(let ((it ,test)) (if it ,then ,else)))
(aif (find 3 '(1 2 3)) (format t "found ~a~%" it))