Reading — step 1 of 5
Learn
Macros are functions that operate on code at compile time. Lisp's killer feature.
A macro takes unevaluated code (as lists/symbols) and returns code that gets compiled.
(defmacro when-positive (n &body body)
`(if (> ,n 0)
(progn ,@body)
nil))
(when-positive 5
(print "hi")
(print "there"))
;; expands to:
;; (if (> 5 0)
;; (progn (print "hi") (print "there"))
;; nil)
Quasiquote / unquote syntax:
`— quasiquote (template),— unquote (substitute the value here),@— splice (substitute and flatten)&body— collect rest as a list
Macro expansion order:
- Reader parses source into lists
- Macros run, transforming lists into other lists
- Compiler compiles the result
This means you can write code that writes code — adding new control structures, abstractions, DSLs.
Example: a swap macro:
(defmacro swap (a b)
(let ((tmp (gensym))) ; gensym = unique symbol — avoids name capture
`(let ((,tmp ,a))
(setf ,a ,b)
(setf ,b ,tmp))))
(let ((x 1) (y 2))
(swap x y)
(format t "~a ~a~%" x y)) ; 2 1
gensym generates a unique symbol — critical to avoid clashing with names in the user's code.
Macros are how Common Lisp libraries like iterate, loop, defclass, with-open-file are built. They're transparent — you can macroexpand to see what they produce.
macroexpand-1 / macroexpand — see what your macro generates:
(macroexpand-1 '(when-positive 5 (print x)))
Discussion
Ask a question, share an insight, or help someone who’s stuck.
Sign in to post a comment or reply.
Loading…