I have a macro that returns an expression based on its parameters:
(defmacro test-params (&key param1 param2)
(if (or param1 param2)
`(+
,@(when param1 `(,param1))
,@(when param2 `(,param2)))
-1))
So when I call (test-params :param1 1 :param2 2) I get returned (+ 1 2)
If I leave off :param1 or :param2 I'll get (+ 1) or (+ 2)
If neither :param1 or :param2 is specified, I'll get -1
This is the way I'd like it to work. Note, this is a contrived example
from a problem I'm working on.
Trouble begins when I try to call test-params from this function:
(defun hard-part (lst)
(let ((p1 (cdr (assoc :p1 lst)))
(p2 (cdr (assoc :p2 lst))))
(test-params :param1 p1 :param2 p2))))
Idealy, this function would get the parameters from a passed-in assoc
list and call test-params. This does not work (it was not obvious to me
at first, but I see why now). I have it working by using the following
function:
(defun hard-part (lst)
(let ((p1 (cdr (assoc :p1 lst)))
(p2 (cdr (assoc :p2 lst))))
(eval `(test-params :param1 ,p1 :param2 ,p2))))
Somehow I feel this is not the best way. Is there a better/cleaner way
of accomplishing this? Basically I want to call the macro with
parameters that may or may not be specified in an assoc list.
Thanks
+ ·············@gmail.com:
| I have a macro that returns an expression based on its parameters:
|
| (defmacro test-params (&key param1 param2)
| (if (or param1 param2)
| `(+
| ,@(when param1 `(,param1))
| ,@(when param2 `(,param2)))
| -1))
|
| So when I call (test-params :param1 1 :param2 2) I get returned (+ 1 2)
| If I leave off :param1 or :param2 I'll get (+ 1) or (+ 2)
| If neither :param1 or :param2 is specified, I'll get -1
| This is the way I'd like it to work. Note, this is a contrived example
| from a problem I'm working on.
|
| Trouble begins when I try to call test-params from this function:
|
| (defun hard-part (lst)
| (let ((p1 (cdr (assoc :p1 lst)))
| (p2 (cdr (assoc :p2 lst))))
| (test-params :param1 p1 :param2 p2))))
|
| Idealy, this function would get the parameters from a passed-in assoc
| list and call test-params. This does not work (it was not obvious to me
| at first, but I see why now). I have it working by using the following
| function:
|
| (defun hard-part (lst)
| (let ((p1 (cdr (assoc :p1 lst)))
| (p2 (cdr (assoc :p2 lst))))
| (eval `(test-params :param1 ,p1 :param2 ,p2))))
|
| Somehow I feel this is not the best way. Is there a better/cleaner way
| of accomplishing this? Basically I want to call the macro with
| parameters that may or may not be specified in an assoc list.
I don't quite see why you need a macro for this in the first place.
You have probably figured out that test-params doesn't do what you
want unless you pass in an /explicit/ nil, or omit a keyword
parameter, right? But in your application, what you need to know is
if the parameter is /in fact/ nil or not. Rewriting it as a function
should help:
(defun test-params (&key param1 param2)
(cond ((and param1 param2) (+ param1 param2))
(param1 param1)
(param2 param2)
(t -1)))
--
* Harald Hanche-Olsen <URL:http://www.math.ntnu.no/~hanche/>
- Debating gives most of us much more psychological satisfaction
than thinking does: but it deprives us of whatever chance there is
of getting closer to the truth. -- C.P. Snow
+ Harald Hanche-Olsen <······@math.ntnu.no>:
| (defun test-params (&key param1 param2)
| (cond ((and param1 param2) (+ param1 param2))
| (param1 param1)
| (param2 param2)
| (t -1)))
Which could be written more concisely, if perhaps less transparently, as
(defun test-params (&key param1 param2)
(if (and param1 param2)
(+ param1 param2)
(or param1 param2 -1)))
--
* Harald Hanche-Olsen <URL:http://www.math.ntnu.no/~hanche/>
- Debating gives most of us much more psychological satisfaction
than thinking does: but it deprives us of whatever chance there is
of getting closer to the truth. -- C.P. Snow
·············@gmail.com writes:
> I have a macro that returns an expression based on its parameters:
>
> (defmacro test-params (&key param1 param2)
> (if (or param1 param2)
> `(+
> ,@(when param1 `(,param1))
> ,@(when param2 `(,param2)))
> -1))
And then you want (let (x y) (test-params :param1 x :param2 y))
to return -1. Your current macro makes the decision whether to
return -1 at macroexpand time, when x and y have not yet been
bound. This can be solved in two ways:
(a) Change the macro so that it checks the nullity of the
parameter forms at run time:
(defmacro test-params (&key param1 param2)
`(if (or ,param1 ,param2)
(apply #'+ `(,@(when ,param1 `(,,param1))
,@(when ,param2 `(,,param2))))
-1))
However, this evaluates the parameter forms multiple times, which
causes problems if the forms have side effects.
(b) Use a function instead:
(defun test-params (&key param1 param2)
(if (or param1 param2)
(apply #'+ `(,@(when param1 `(,param1))
,@(when param2 `(,param2))))
-1))
Kalle Olavi Niemitalo wrote:
> ·············@gmail.com writes:
>
>
>>I have a macro that returns an expression based on its parameters:
>>
>>(defmacro test-params (&key param1 param2)
>> (if (or param1 param2)
>> `(+
>> ,@(when param1 `(,param1))
>> ,@(when param2 `(,param2)))
>> -1))
>
>
> And then you want (let (x y) (test-params :param1 x :param2 y))
> to return -1. Your current macro makes the decision whether to
> return -1 at macroexpand time, when x and y have not yet been
> bound. This can be solved in two ways:
>
> (a) Change the macro so that it checks the nullity of the
> parameter forms at run time:
>
> (defmacro test-params (&key param1 param2)
> `(if (or ,param1 ,param2)
> (apply #'+ `(,@(when ,param1 `(,,param1))
> ,@(when ,param2 `(,,param2))))
> -1))
>
> However, this evaluates the parameter forms multiple times, which
> causes problems if the forms have side effects.
>
> (b) Use a function instead:
>
> (defun test-params (&key param1 param2)
> (if (or param1 param2)
> (apply #'+ `(,@(when param1 `(,param1))
> ,@(when param2 `(,param2))))
> -1))
Other suggestions:
(defun test-params (&key (param1 0 param1-p)
(param2 0 param2-p))
(if (or param1-p param2-p)
(+ param1 param2)
-1))
(defun test-params (&rest params)
(declare (dynamic-extent params))
(if params
(apply #'+ params)
-1))
Pascal