Sorry for the clumsy title but i'm having a hard time describing what i'm looking for in a few words ...
I'm working on a Common Lisp DSL project and I'm wondering if the following is possible:
The DSL might have a couple of functions
(defun foo (&rest rest))
and
(defun bar (arg))
that'll be used in the following way:
(foo (bar 100) (bar 200) (bar 300) (bar 400) (bar 500))
etc.
Now, that's a lot of redundant typing, so I wonder if it's possible to create an expander macro that'll allow for
(foo (expand bar 100 200 300 400 500))
without changing foo
itself ?
No, this can't be done without changing the signature of the functions you are defining (or possibly using some hairy thing which redefines macroexpansion): you have what I call a 'spread/nospread impedance mismatch' which can't be resolved with a standard macro in CL.
A 'nospread' function is a function which wraps all of its arguments into one formal. A 'spread' function has one formal per argument. I learned these terms when using InterLisp: they may predate that, but they seem to be mostly unused now. CL functions can be only partly-nospread ((foo bar &rest more)
). Your foo
is nospread.
A spread/nospread impedance mismatch is when you have a spread function but want a nospread one, or vice versa. It is almost always a sign of a design problem. The workaround for spread/nospread problems generally involves apply
.
Your problem is that foo
is a nospread function: it turns all its arguments into one list, but you want the macro to treat it as a spread function, handing it a single list of arguments.
In particular, in CL an expression like (x (y ...))
can never be turned into (x a1 a2 ...)
for any y
, function or macro (but see below), and this is what you need to happen.
In your case you want something like
(foo (expand bar a b ...)
To turn into
(foo (bar a) (bar b)
And that can't happen.
There have been Lisps which had things which were called 'splicing macros' in which a macro's expansion could be 'spliced' into a list, in the way that ,@
does for backquote. It may be that there are splicing macro packages for CL, and it may even be that they are portable: you can get a long way with *macroexpand-hook*
. But standard CL macros can not do this.