Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Procedural Macros

Definition:

(define-macro name (arg1 arg2 ... $ENV)
  body)

Special argument $ENV: The macro receives the environment at the call site, enabling hygiene and context-aware transformation.

Example:

(define-macro unless (test . body)
  `(if ,test 'false (progn ,@body)))

;; Usage:
(unless (< x 0)
  (print "positive")
  (inc x))

;; Expands to:
(if (< x 0)
    'false
    (progn
      (print "positive")
      (inc x)))

Quasiquotation (backquote):

`(list ,x ,@xs)

;; With x=42, xs=[1,2,3]:
[list, 42, 1, 2, 3]

Backquote operators:

  • ` (backquote): Quote with holes
  • , (comma / unquote): Insert value
  • ,@ (comma-at / unquote-splicing): Splice list

Example of manual hygiene:

;; CAREFUL: This macro can capture variables
(define-macro my-swap (a b)
  `(let ((temp ,a))
     (set ,a ,b)
     (set ,b temp)))  ; 'temp' might collide with user code

;; Better: use a very unlikely variable name
(define-macro my-swap (a b)
  `(let ((___swap_temp_internal___ ,a))
     (set ,a ,b)
     (set ,b ___swap_temp_internal___)))