Defining new macros with define-modify-macro
One easy way to define new convenience macros for our needs is define-modify-macro . This is a handy macro that can create other macros for us.
Syntax:
define-modify-macro lambda list function name [documentation]
⇒ name
We must specify the name of the new macro, a list of parameters (not including the place there) and the function symbol that will be used for processing.
Usage example:
(define-modify-macro togglef () not "togglef modifies place, changing nil value to t and non-nil value to nil") (define-modify-macro mulf (&rest args) * "mulf modifies place, assigning product to it") (define-modify-macro divf (&rest args) / "divf modifies place, assigning result of division to it")
However, define-modify-macro cannot be used for arbitrary processing. Here we must take a look at other possibilities.
get-setf-expansion function
The get-setf-expansion function does not create any macros, but provides information that we can use to write our own.
Syntax:
get-setf-expand space and additional environment
⇒ vars, ramparts, vaults, writing form, reader form
As you can see, it returns a bunch of values, so at a glance it can be confusing. Let's try this with an example:
CL-USER> (defvar *array*
Writing an xf Macro
It seems we now have all the information to write our xf macro:
(defmacro xf (fn place &rest args &environment env) (multiple-value-bind (vars forms var set access) (get-setf-expansion place env) (let ((g (gensym))) `(let* ((,g ,fn) ; assign supplied function to generated symbol ,@(mapcar #'list vars forms) ; generate pairs (variable value) (,(car var) (funcall ,g ,access ,@args))) ; call supplied function ; and save the result, we use reader-form here to get intial value ,set)))) ; just put writer-from here as provided
Note that the xf macro accepts the evironment variable and passes it to get-setf-expansion . This variable is necessary to ensure that any lexical bindings or definitions are set up in the compilation environment.
Try:
CL-USER> (defvar *var* '(("foo" . "bar") ("baz" . "qux"))) *VAR* CL-USER> (xf #'reverse (cdr (second *var*))) "xuq" CL-USER> *var* (("foo" . "bar") ("baz" . "xuq"))
extensions:
(LET* ((
I hope this information is helpful.
This answer is based on Paul Graham's On Lisp , section 12.4 More Complex Utilities.