-
Notifications
You must be signed in to change notification settings - Fork 34
Defining New Macros in LISP
Recommendation:
Before defining new macros, consider if they are truly necessary. While macros can make code more readable, they can also complicate debugging.
Basic Structure of a Macro:
In LISP, a macro can be defined using the following structure:
(defmacro macro-name (parameters)
"Documentation"
macro-body)
What are Macros?
Macros allow you to create custom syntax in LISP. They work by transforming code and introducing new notations. Unlike functions, the body of a macro is computed during compilation. This means you can use macros to generate code that gets expanded at compile-time.
Examples:
- A simple macro:
(defmacro forty-two () (* 2 21))
Using (forty-two)
is the same as directly writing 42
.
- A macro with quoted LISP expressions:
(defmacro forty-two () '(* 2 21))
Here, (forty-two)
is equivalent to (* 2 21)
, which evaluates to 42
during runtime.
Macros accept parameters like functions. You can use &optional
, &key
, and &rest
. Additionally, macros offer &body
, which is like &rest
but more descriptive, aiding both human readers and development tools.
For ease of writing and reading complex expressions, LISP macros use backquotes (`) and commas (,). The backquote marks the start of an expression. Within that expression, a comma indicates subexpressions to be evaluated. Others are left quoted.
Consider the measure-time
macro:
(defmacro measure-time (type &body body)
"Description"
`(let ((start ...)
(value ...))
,...
value))
In this macro, ,
tells LISP which parts to evaluate and which to leave quoted.
Splicing with ,@
lets you remove the outermost parentheses. It's useful when you want the code inside a block like (progn ...)
. The measure-time
macro showcases this.
This macro simulates a robot's actions:
(defmacro with-simulated-robot (&body body)
`(let ((results
(proj:...
(cpl-impl:...
,@body))))
(car ...)))
When you use:
(with-simulated-robot
some code)
The "body" contains "some code". The macro evaluates as much of the body as possible during macro expansion. Then, it passes results to other functions/macros that run during runtime. Given the name "with-simulated-robot", it's clear that the code should simulate a robot's actions in real-time, not during macro expansion.
In essence, LISP macros allow for powerful code transformations. They enable you to extend the language's syntax, but it's essential to use them judiciously to maintain code clarity and ease of debugging.