cl: Macro Bindings
4.3.3 Macro Bindings
--------------------
These forms create local macros and “symbol macros”.
-- Macro: cl-macrolet (bindings...) forms...
This form is analogous to ‘cl-flet’, but for macros instead of
functions. Each BINDING is a list of the same form as the
arguments to ‘cl-defmacro’ (i.e., a macro name, argument list, and
macro-expander forms). The macro is defined accordingly for use
within the body of the ‘cl-macrolet’.
Because of the nature of macros, ‘cl-macrolet’ is always lexically
scoped. The ‘cl-macrolet’ binding will affect only calls that
appear physically within the body FORMS, possibly after expansion
of other macros in the body.
-- Macro: cl-symbol-macrolet (bindings...) forms...
This form creates “symbol macros”, which are macros that look like
variable references rather than function calls. Each BINDING is a
list ‘(VAR EXPANSION)’; any reference to VAR within the body FORMS
is replaced by EXPANSION.
(setq bar '(5 . 9))
(cl-symbol-macrolet ((foo (car bar)))
(cl-incf foo))
bar
⇒ (6 . 9)
A ‘setq’ of a symbol macro is treated the same as a ‘setf’. I.e.,
‘(setq foo 4)’ in the above would be equivalent to ‘(setf foo 4)’,
which in turn expands to ‘(setf (car bar) 4)’.
Likewise, a ‘let’ or ‘let*’ binding a symbol macro is treated like
a ‘cl-letf’ or ‘cl-letf*’. This differs from true Common Lisp,
where the rules of lexical scoping cause a ‘let’ binding to shadow
a ‘symbol-macrolet’ binding. In this package, such shadowing does
not occur, even when ‘lexical-binding’ is ‘t’. (This behavior
predates the addition of lexical binding to Emacs Lisp, and may
change in future to respect ‘lexical-binding’.) At present in this
package, only ‘lexical-let’ and ‘lexical-let*’ will shadow a symbol
macro. Obsolete Lexical Binding.
There is no analogue of ‘defmacro’ for symbol macros; all symbol
macros are local. A typical use of ‘cl-symbol-macrolet’ is in the
expansion of another macro:
(cl-defmacro my-dolist ((x list) &rest body)
(let ((var (cl-gensym)))
(list 'cl-loop 'for var 'on list 'do
(cl-list* 'cl-symbol-macrolet
(list (list x (list 'car var)))
body))))
(setq mylist '(1 2 3 4))
(my-dolist (x mylist) (cl-incf x))
mylist
⇒ (2 3 4 5)
In this example, the ‘my-dolist’ macro is similar to ‘dolist’
(Iteration) except that the variable ‘x’ becomes a true
reference onto the elements of the list. The ‘my-dolist’ call
shown here expands to
(cl-loop for G1234 on mylist do
(cl-symbol-macrolet ((x (car G1234)))
(cl-incf x)))
which in turn expands to
(cl-loop for G1234 on mylist do (cl-incf (car G1234)))
Loop Facility, for a description of the ‘cl-loop’ macro.
This package defines a nonstandard ‘in-ref’ loop clause that works
much like ‘my-dolist’.