Re: Newbie doubt with macros ` , ,@
- From: tar@xxxxxxxxxxxxx (Thomas A. Russ)
- Date: 04 Mar 2008 12:19:41 -0800
Ashrentum <ashrentum@xxxxxxxxx> writes:
Hi. It is a newbie question about how parameters and vars are treated
inside macros and how to deal with the commas, back quotes, and commas-
at. I give this silly example:
(defmacro mymacro ()
(let ((name (gensym))
`(list ,(dotimes (,name 10 ,name) (print ,name))))) ;1-error
That is, I want, for whatever reasons, that the index variable for the
dotimes was the name generated by (gensym).
It is not possible to write commas inside a comma, so how can I get
inside of dotimes the name generated by (gensym)?
Well, the issue here isn't so much the use of commas but issues of what
does and does not get evaluated when you pass the values. It would be
possible to solve some of this using EVAL, but that is generally not
recommended.
Instead, it often makes sense to think carefully about what should be a
macro and what should be a function.
How can you call first an internal macro with parameters of the outer
macro?
You might not want the internal item to be a macro. It is quite
legitimate and common to have helper FUNCTIONs that build part of the
code that a macro uses to generate an expansion.
My scenario is this:
I had to define in one supermacro many bindings that were exactly the
same, i.e. different variables but with the same value. So for this I
thought that could be nice define another macro that got the value in
one parameter and a list of variables to bind with:
(defmacro let-samevars (definition &rest vars)
(let ((defs))
(dolist (var vars)
(push (list var definition) defs))
`',(reverse defs)))
Well, consider doing this as a function, since the effect of using a
macro is that DEFINITION doesn't get evaluated. And below, you want it
to get evaluated.
(defun distribute-value (vars value)
;; Creates a list where each element of VARS is paired with VALUE
(let ((defs))
(dolist (var vars (reverse defs))
(push (list var value) defs))))
Note: Important warning below.
So a call like this: (let-samevars nil v1 v2 v3) would create: '((v1
nil) (v2 nil) (v3 nil)). Of course, this makes more sense if instead
of nil is a complex expression.
So, let's pretend the supermacro is something like:
(defmacro supermacro ()
(let* ((name (gensym)))
`(let ((,name 5)
,@(let-samevars name v1 v2)) ;2-error
(list ,name v1 v2))))
This then becomes:
(defmacro supermacro ()
(let* ((name (gensym)))
`(let ((,name 5)
,@(distribute-value '(v1 v2) name)) ;; CHANGED
(list ,name v1 v2))))
If having to quote the list of variables annoys you, you can wrap a
macro around that part, perhaps like
(defmacro distribute ((&rest vars) value)
`(distribute-value ',vars ,value))
and then you would invoke this macro like
(distribute (v1 v2 v3) name)
and the variable list will not be evaluated (because it gets quoted in
the macro body, whereas name will be because it is passed unquoted
through to the underlying function, which will evaluate the argument.
Is there a combination of commas that I don't know?
No, but there's a combination of macros and functions that you aren't
using.
Important Warning:
The only caveat is that you need to make sure that the DISTRIBUTE-VALUE
function is defined in the appropriate evaluation and compilation
environment where it is being used. If you want to define a macro (like
I do below) that depends on DISTRIBUTE-VALUE and then use that macro in
the same file that both the macro and the function are defined, you will
need to wrap the function in an appropriate eval-when form:
(eval-when (:execute :compile-toplevel :load-toplevel)
(defun distribute-value ...))
--
Thomas A. Russ, USC/Information Sciences Institute
.
- References:
- Newbie doubt with macros ` , ,@
- From: Ashrentum
- Newbie doubt with macros ` , ,@
- Prev by Date: Re: Chicago Lisp Meetup?
- Next by Date: Re: is free, open source software ethical?
- Previous by thread: Re: Newbie doubt with macros ` , ,@
- Next by thread: sbcl exit hooks
- Index(es):
Relevant Pages
|
Loading