I am writing a macro which takes a lambda-list as one of its arguments.
Inside the macro i want to delcare a function which has &rest arguments
but uses destructuring-bind to validate the argument list.
Is there a way to keep tell the compiler to ignore the fact that i'm
binding
variables and never using them when i do not even know the names
of the variables i'm not using?
destructuring-bind should have the nice side effect of triggering
a runtime error if the function is called with incompatible arguments.
E.g., if lambda-list is (a b &key foo) but the function gets called
with
(1 2 3) or (1 2 :bar 3), then destructuring-bind should trigger an
error.
But if called with (1 2) or (1 2 :foo 3), then dispatch should get
called
happily with that list as its second argument.
Any suggestions?
(defmacro def-pap-fun (name lambda-list &rest body)
`(let ((pap-function (make-instance 'pap-function :name ',name
:lambda-list ',lambda-list)))
(add-pap ,name ,lambda-list t
,@body)
(defun ,name (&rest args)
(destructuring-bind ,lambda-list args
nil) ;;;<<<<----- here i am not using any of lambda-list
(dispatch pap-function args))))
Jimka wrote:
> I am writing a macro which takes a lambda-list as one of its arguments.
>
> Inside the macro i want to delcare a function which has &rest arguments
> but uses destructuring-bind to validate the argument list.
> Is there a way to keep tell the compiler to ignore the fact that i'm
> binding
> variables and never using them when i do not even know the names
> of the variables i'm not using?
>
> destructuring-bind should have the nice side effect of triggering
> a runtime error if the function is called with incompatible arguments.
> E.g., if lambda-list is (a b &key foo) but the function gets called
> with
> (1 2 3) or (1 2 :bar 3), then destructuring-bind should trigger an
> error.
> But if called with (1 2) or (1 2 :foo 3), then dispatch should get
> called
> happily with that list as its second argument.
>
> Any suggestions?
As far as I know (and I have looked very hard ;), there is no way to
achieve this. You have to parse the lambda list to find the variable
names, and then use an ignore declaration with those names.
Unfortunately, parsing lambda lists means that you have to deal with
many special cases. :(
> (defmacro def-pap-fun (name lambda-list &rest body)
> `(let ((pap-function (make-instance 'pap-function :name ',name
> :lambda-list ',lambda-list)))
> (add-pap ,name ,lambda-list t
> ,@body)
> (defun ,name (&rest args)
> (destructuring-bind ,lambda-list args
> nil) ;;;<<<<----- here i am not using any of lambda-list
> (dispatch pap-function args))))
Pascal
--
My website: http://p-cos.net
Common Lisp Document Repository: http://cdr.eurolisp.org
Closer to MOP & ContextL: http://common-lisp.net/project/closer/
Is the compiler allowed to ignore my entire destructuring-bind since
i'm not doing anything with the parameters? This would seem like
a compiler bug, because simply because the variables are not
explicitly used does not mean there are no important side effects,
namely the rasing of runtime errors if the parameters do not match
the arguments.
-jim
Pascal Costanza wrote:
> Jimka wrote:
> > I am writing a macro which takes a lambda-list as one of its arguments.
> >
> > Inside the macro i want to delcare a function which has &rest arguments
> > but uses destructuring-bind to validate the argument list.
> > Is there a way to keep tell the compiler to ignore the fact that i'm
> > binding
> > variables and never using them when i do not even know the names
> > of the variables i'm not using?
> >
> > destructuring-bind should have the nice side effect of triggering
> > a runtime error if the function is called with incompatible arguments.
> > E.g., if lambda-list is (a b &key foo) but the function gets called
> > with
> > (1 2 3) or (1 2 :bar 3), then destructuring-bind should trigger an
> > error.
> > But if called with (1 2) or (1 2 :foo 3), then dispatch should get
> > called
> > happily with that list as its second argument.
> >
> > Any suggestions?
>
> As far as I know (and I have looked very hard ;), there is no way to
> achieve this. You have to parse the lambda list to find the variable
> names, and then use an ignore declaration with those names.
>
> Unfortunately, parsing lambda lists means that you have to deal with
> many special cases. :(
>
>
> > (defmacro def-pap-fun (name lambda-list &rest body)
> > `(let ((pap-function (make-instance 'pap-function :name ',name
> > :lambda-list ',lambda-list)))
> > (add-pap ,name ,lambda-list t
> > ,@body)
> > (defun ,name (&rest args)
> > (destructuring-bind ,lambda-list args
> > nil) ;;;<<<<----- here i am not using any of lambda-list
> > (dispatch pap-function args))))
>
>
> Pascal
>
> --
> My website: http://p-cos.net
> Common Lisp Document Repository: http://cdr.eurolisp.org
> Closer to MOP & ContextL: http://common-lisp.net/project/closer/
Misunderstanding: When I said "there is no way to achieve this", I meant
that there is no way to tell the compiler to ignore all unused variables
in some lexical scope.
The compiler is indeed not allowed to ignore a destructuring-bind with
an empty body.
Maybe the following hack provides a usable workaround:
(handler-bind ((warning #'muffle-warning))
(eval `(destructuring-bind ,lambda-list ,args)))
[Untested.]
Pascal
Jimka wrote:
> Is the compiler allowed to ignore my entire destructuring-bind since
> i'm not doing anything with the parameters? This would seem like
> a compiler bug, because simply because the variables are not
> explicitly used does not mean there are no important side effects,
> namely the rasing of runtime errors if the parameters do not match
> the arguments.
> -jim
>
>
> Pascal Costanza wrote:
>> Jimka wrote:
>>> I am writing a macro which takes a lambda-list as one of its arguments.
>>>
>>> Inside the macro i want to delcare a function which has &rest arguments
>>> but uses destructuring-bind to validate the argument list.
>>> Is there a way to keep tell the compiler to ignore the fact that i'm
>>> binding
>>> variables and never using them when i do not even know the names
>>> of the variables i'm not using?
>>>
>>> destructuring-bind should have the nice side effect of triggering
>>> a runtime error if the function is called with incompatible arguments.
>>> E.g., if lambda-list is (a b &key foo) but the function gets called
>>> with
>>> (1 2 3) or (1 2 :bar 3), then destructuring-bind should trigger an
>>> error.
>>> But if called with (1 2) or (1 2 :foo 3), then dispatch should get
>>> called
>>> happily with that list as its second argument.
>>>
>>> Any suggestions?
>> As far as I know (and I have looked very hard ;), there is no way to
>> achieve this. You have to parse the lambda list to find the variable
>> names, and then use an ignore declaration with those names.
>>
>> Unfortunately, parsing lambda lists means that you have to deal with
>> many special cases. :(
>>
>>
>>> (defmacro def-pap-fun (name lambda-list &rest body)
>>> `(let ((pap-function (make-instance 'pap-function :name ',name
>>> :lambda-list ',lambda-list)))
>>> (add-pap ,name ,lambda-list t
>>> ,@body)
>>> (defun ,name (&rest args)
>>> (destructuring-bind ,lambda-list args
>>> nil) ;;;<<<<----- here i am not using any of lambda-list
>>> (dispatch pap-function args))))
>>
>> Pascal
>>
>> --
>> My website: http://p-cos.net
>> Common Lisp Document Repository: http://cdr.eurolisp.org
>> Closer to MOP & ContextL: http://common-lisp.net/project/closer/
>
--
My website: http://p-cos.net
Common Lisp Document Repository: http://cdr.eurolisp.org
Closer to MOP & ContextL: http://common-lisp.net/project/closer/
Hi Pascal, does your closer package provide a usable lambda list
parser?
You probably had to write one and make it work on lots of different
implementations, right?
-jim
Pascal Costanza wrote:
> Misunderstanding: When I said "there is no way to achieve this", I meant
> that there is no way to tell the compiler to ignore all unused variables
> in some lexical scope.
>
> The compiler is indeed not allowed to ignore a destructuring-bind with
> an empty body.
>
> Maybe the following hack provides a usable workaround:
>
> (handler-bind ((warning #'muffle-warning))
> (eval `(destructuring-bind ,lambda-list ,args)))
>
>
> [Untested.]
>
> Pascal
>
> Jimka wrote:
> > Is the compiler allowed to ignore my entire destructuring-bind since
> > i'm not doing anything with the parameters? This would seem like
> > a compiler bug, because simply because the variables are not
> > explicitly used does not mean there are no important side effects,
> > namely the rasing of runtime errors if the parameters do not match
> > the arguments.
> > -jim
> >
> >
> > Pascal Costanza wrote:
> >> Jimka wrote:
> >>> I am writing a macro which takes a lambda-list as one of its arguments.
> >>>
> >>> Inside the macro i want to delcare a function which has &rest arguments
> >>> but uses destructuring-bind to validate the argument list.
> >>> Is there a way to keep tell the compiler to ignore the fact that i'm
> >>> binding
> >>> variables and never using them when i do not even know the names
> >>> of the variables i'm not using?
> >>>
> >>> destructuring-bind should have the nice side effect of triggering
> >>> a runtime error if the function is called with incompatible arguments.
> >>> E.g., if lambda-list is (a b &key foo) but the function gets called
> >>> with
> >>> (1 2 3) or (1 2 :bar 3), then destructuring-bind should trigger an
> >>> error.
> >>> But if called with (1 2) or (1 2 :foo 3), then dispatch should get
> >>> called
> >>> happily with that list as its second argument.
> >>>
> >>> Any suggestions?
> >> As far as I know (and I have looked very hard ;), there is no way to
> >> achieve this. You have to parse the lambda list to find the variable
> >> names, and then use an ignore declaration with those names.
> >>
> >> Unfortunately, parsing lambda lists means that you have to deal with
> >> many special cases. :(
> >>
> >>
> >>> (defmacro def-pap-fun (name lambda-list &rest body)
> >>> `(let ((pap-function (make-instance 'pap-function :name ',name
> >>> :lambda-list ',lambda-list)))
> >>> (add-pap ,name ,lambda-list t
> >>> ,@body)
> >>> (defun ,name (&rest args)
> >>> (destructuring-bind ,lambda-list args
> >>> nil) ;;;<<<<----- here i am not using any of lambda-list
> >>> (dispatch pap-function args))))
> >>
> >> Pascal
> >>
> >> --
> >> My website: http://p-cos.net
> >> Common Lisp Document Repository: http://cdr.eurolisp.org
> >> Closer to MOP & ContextL: http://common-lisp.net/project/closer/
> >
>
>
> --
> My website: http://p-cos.net
> Common Lisp Document Repository: http://cdr.eurolisp.org
> Closer to MOP & ContextL: http://common-lisp.net/project/closer/
Jimka wrote:
> Hi Pascal, does your closer package provide a usable lambda list
> parser?
> You probably had to write one and make it work on lots of different
> implementations, right?
In the published code, I only use ad hoc "parsers" that do exactly what
is required in the respective situation, and nothing else. So they are
unfortunately not very reusable.
I have experimented with some ideas for reusable lambda list parsers,
but haven't come up with something that I am sufficiently happy with and
that I would like to make publicly available.
If you're really very interested, I can send you what I have privately,
but don't hope for something that's immediately usable.
The various open source CL implementations must have lambda list
parsers, maybe there is something to look for.
Pascal
--
My website: http://p-cos.net
Common Lisp Document Repository: http://cdr.eurolisp.org
Closer to MOP & ContextL: http://common-lisp.net/project/closer/
Pascal Costanza <··@p-cos.net> writes:
> Jimka wrote:
>> Hi Pascal, does your closer package provide a usable lambda list
>> parser?
>> You probably had to write one and make it work on lots of different
>> implementations, right?
>
> In the published code, I only use ad hoc "parsers" that do exactly
> what is required in the respective situation, and nothing else. So
> they are unfortunately not very reusable.
>
> I have experimented with some ideas for reusable lambda list parsers,
> but haven't come up with something that I am sufficiently happy with
> and that I would like to make publicly available.
>
> If you're really very interested, I can send you what I have
> privately, but don't hope for something that's immediately usable.
>
> The various open source CL implementations must have lambda list
> parsers, maybe there is something to look for.
I've got a lambda list parser in:
http://www.informatimago.com/develop/lisp/index.html
http://darcs.informatimago.com/darcs/public/lisp/common-lisp/source.lisp
But note that I don't treat implementation specific lambda list
keywords (but those can be used only with macros, so this won't be a
problem for you).
--
__Pascal Bourguignon__ http://www.informatimago.com/
THIS IS A 100% MATTER PRODUCT: In the unlikely event that this
merchandise should contact antimatter in any form, a catastrophic
explosion will result.
+ "Jimka" <·····@rdrop.com>:
| Is there a way to keep tell the compiler to ignore the fact that i'm
| binding variables and never using them when i do not even know the
| names of the variables i'm not using?
Will an IGNORABLE declaration work for you?
Or maybe I missed your whole point ...
--
* Harald Hanche-Olsen <URL:http://www.math.ntnu.no/~hanche/>
- It is undesirable to believe a proposition
when there is no ground whatsoever for supposing it is true.
-- Bertrand Russell
If you have an idea it would be great to hear Harald, what should i
make IGNORABLE?
If lambda-list is (a b) then i want a and to be ignorable,
If lambda-list is (a b &rest c) then i want a b and c to be ignorable,
If lambda-list is (a b &key (c 100) &rest d) then i want a b c and d to
be ignorable.
But the problem is lambda-list is potentially different every time the
macro is expanded.
So the problem is how to calculate the list of variables to ignore.
Any ideas Harald?
kind regards
-jim
Harald Hanche-Olsen wrote:
> + "Jimka" <·····@rdrop.com>:
>
> | Is there a way to keep tell the compiler to ignore the fact that i'm
> | binding variables and never using them when i do not even know the
> | names of the variables i'm not using?
>
> Will an IGNORABLE declaration work for you?
> Or maybe I missed your whole point ...
>
> --
> * Harald Hanche-Olsen <URL:http://www.math.ntnu.no/~hanche/>
> - It is undesirable to believe a proposition
> when there is no ground whatsoever for supposing it is true.
> -- Bertrand Russell
Jimka wrote:
> If lambda-list is (a b) then i want a and to be ignorable,
> If lambda-list is (a b &rest c) then i want a b and c to be ignorable,
> If lambda-list is (a b &key (c 100) &rest d) then i want a b c and d
> to be ignorable.
> But the problem is lambda-list is potentially different every time the
> macro is expanded.
> So the problem is how to calculate the list of variables to ignore.
[...]
Do you mean something like this?
Carl Taylor
(defun flatten (in-list &optional accumulator)
"From: Norvig's PAIP."
(cond ((null in-list) accumulator)
((atom in-list) (cons in-list accumulator))
(t
(flatten (car in-list)
(flatten (cdr in-list) accumulator)))))
(defmacro foo (name lambda-list)
(let ((l-arg-list
(delete-if #'(lambda (x) (char= #\& (schar (string x) 0)))
(delete-if (complement #'symbolp)
(flatten lambda-list)))))
`(defun ,name (&rest args)
(destructuring-bind ,l-arg-list args
(declare (ignore ,@l-arg-list))))))
(pprint (macroexpand '(foo baz (a b))))
(pprint (macroexpand '(foo baz (a b &rest c))))
(pprint (macroexpand '(foo baz (a b &key (c 100) &rest d))))
On Sat, 11 Nov 2006 15:58:42 +0100, Jimka <·····@rdrop.com> wrote:
define-compiler-macro takes care of decisions that must be delayed to
compile time.
--
Using Opera's revolutionary e-mail client: http://www.opera.com/mail/
Interesting John,
So how can i use define-compiler-macro to declare
ignorable the variables declared in the lambda-list variable?
(defmacro foo (lambda-list fun)
`(defun bar (@rest args)
(destructuring-bind ,lambda-list args
nil)
(apply ,fun args)))
John Thingstad wrote:
> On Sat, 11 Nov 2006 15:58:42 +0100, Jimka <·····@rdrop.com> wrote:
>
>
> define-compiler-macro takes care of decisions that must be delayed to
> compile time.
>
>
> --
> Using Opera's revolutionary e-mail client: http://www.opera.com/mail/
+ "Jimka" <·····@rdrop.com>:
| If you have an idea it would be great to hear Harald, what should i
| make IGNORABLE?
My response was apparently based on a misreading of your original
post, as explained in a followup to Pascal Costanza. My entire point
was to point out the difference between IGNORE and IGNORABLE: With
the latter, you don't need to know which variables you're not using,
but you do of course need to know which variables are being bound.
Since I thought your problem was of the former kind rather than the
latter, my response was reasonable.
Now I see that others have provided substantial help in the meantime,
so my input is certainly not needed. But I would have appreciated it
if you had laid off the sarcasm. It was uncalled for.
--
* Harald Hanche-Olsen <URL:http://www.math.ntnu.no/~hanche/>
- It is undesirable to believe a proposition
when there is no ground whatsoever for supposing it is true.
-- Bertrand Russell
Harald Hanche-Olsen wrote:
> + "Jimka" <·····@rdrop.com>:
>
> | Is there a way to keep tell the compiler to ignore the fact that i'm
> | binding variables and never using them when i do not even know the
> | names of the variables i'm not using?
>
> Will an IGNORABLE declaration work for you?
> Or maybe I missed your whole point ...
For an ignorable declaration, you need the names of the variables that
should be ignorable. In the original code, the lambda list isn't
destructured, though, so it's not obvious what the variable names are.
A (declare (ignorable *)) form would indeed sometimes be useful to
suppress warnings about any unused variables.
Pascal
--
My website: http://p-cos.net
Common Lisp Document Repository: http://cdr.eurolisp.org
Closer to MOP & ContextL: http://common-lisp.net/project/closer/
+ Pascal Costanza <··@p-cos.net>:
| Harald Hanche-Olsen wrote:
|> + "Jimka" <·····@rdrop.com>:
|> | Is there a way to keep tell the compiler to ignore the fact that
|> i'm
|> | binding variables and never using them when i do not even know the
|> | names of the variables i'm not using?
|> Will an IGNORABLE declaration work for you?
|> Or maybe I missed your whole point ...
|
| For an ignorable declaration, you need the names of the variables that
| should be ignorable. In the original code, the lambda list isn't
| destructured, though, so it's not obvious what the variable names are.
Ah. That was the point I missed. I thought the problem was that the
OP didn't want to parse the body for unused variables.
--
* Harald Hanche-Olsen <URL:http://www.math.ntnu.no/~hanche/>
- It is undesirable to believe a proposition
when there is no ground whatsoever for supposing it is true.
-- Bertrand Russell
From: Wade Humeniuk
Subject: Re: how to declare ignorable in destructuring-bind
Date:
Message-ID: <Tgp5h.2752$ae6.722@clgrps13>
Jimka wrote:
> I am writing a macro which takes a lambda-list as one of its arguments.
>
> Inside the macro i want to delcare a function which has &rest arguments
> but uses destructuring-bind to validate the argument list.
> Is there a way to keep tell the compiler to ignore the fact that i'm
> binding
> variables and never using them when i do not even know the names
> of the variables i'm not using?
>
> destructuring-bind should have the nice side effect of triggering
> a runtime error if the function is called with incompatible arguments.
> E.g., if lambda-list is (a b &key foo) but the function gets called
> with
> (1 2 3) or (1 2 :bar 3), then destructuring-bind should trigger an
> error.
> But if called with (1 2) or (1 2 :foo 3), then dispatch should get
> called
> happily with that list as its second argument.
>
> Any suggestions?
(defmacro def-pap-fun (name lambda-list &rest body)
`(let ((pap-function (make-instance 'pap-function :name ',name
:lambda-list ',lambda-list)))
(add-pap ,name ,lambda-list t
,@body)
(defun ,name (&rest args)
(destructuring-bind ,lambda-list args
(declare (ignorable ,@(mapcar (lambda (arg)
(etypecase arg
(cons (car arg))
(atom arg)))
(remove-if
(lambda (arg)
(member arg '(&key &rest)))
lambda-list))))
nil) ;;;<<<<----- here i am not using any of lambda-list
(dispatch pap-function args))))
CL-USER 3 > (pprint (macroexpand '(def-pap-fun test (a b &key (c 10)) nil)))
(LET ((PAP-FUNCTION
(MAKE-INSTANCE 'PAP-FUNCTION
:NAME
'TEST
:LAMBDA-LIST
'(A B &KEY (C 10)))))
(ADD-PAP TEST (A B &KEY (C 10)) T NIL)
(DEFUN TEST (&REST ARGS)
(DESTRUCTURING-BIND (A B &KEY (C 10)) ARGS (DECLARE (IGNORABLE A B C)) NIL)
(DISPATCH PAP-FUNCTION ARGS)))
CL-USER 4 >
Wade
Hi Wade, i think this is on the right track but not quite there.
But it fails for the following
(pprint (macroexpand '(def-pap-fun test (a b &key ((:c x) 10 used))
nil)))
(LET ((PAP-FUNCTION
(MAKE-INSTANCE 'PAP-FUNCTION
:NAME
'TEST
:LAMBDA-LIST
'(A B &KEY ((:C X) 10 USED)))))
(ADD-PAP TEST (A B &KEY ((:C X) 10 USED)) T NIL)
(DEFUN TEST (&REST ARGS)
(DESTRUCTURING-BIND
(A B &KEY ((:C X) 10 USED))
ARGS
(DECLARE (IGNORABLE A B (:C X))) ;;<<< it should be ignoring X
and USED not (:C X)
NIL)
(DISPATCH PAP-FUNCTION ARGS)))
From: Wade Humeniuk
Subject: Re: how to declare ignorable in destructuring-bind
Date:
Message-ID: <uur5h.2775$ae6.398@clgrps13>
Jimka wrote:
> Hi Wade, i think this is on the right track but not quite there.
> But it fails for the following
>
> (pprint (macroexpand '(def-pap-fun test (a b &key ((:c x) 10 used))
> nil)))
>
> (LET ((PAP-FUNCTION
> (MAKE-INSTANCE 'PAP-FUNCTION
> :NAME
> 'TEST
> :LAMBDA-LIST
> '(A B &KEY ((:C X) 10 USED)))))
> (ADD-PAP TEST (A B &KEY ((:C X) 10 USED)) T NIL)
> (DEFUN TEST (&REST ARGS)
> (DESTRUCTURING-BIND
> (A B &KEY ((:C X) 10 USED))
> ARGS
> (DECLARE (IGNORABLE A B (:C X))) ;;<<< it should be ignoring X
> and USED not (:C X)
> NIL)
> (DISPATCH PAP-FUNCTION ARGS)))
>
There is nothing magic going on with macros, just modify it ...
(Of course the macro could be written with more extensive
error checking)
(defmacro def-pap-fun (name lambda-list &rest body)
`(let ((pap-function (make-instance 'pap-function :name ',name
:lambda-list ',lambda-list)))
(add-pap ,name ,lambda-list t
,@body)
(defun ,name (&rest args)
(destructuring-bind ,lambda-list args
(declare (ignorable ,@(mapcan (lambda (arg)
(etypecase arg
(cons
(destructuring-bind (var init &optional pred)
arg
(declare (ignore init))
(when (consp var) (setf var (cadr var)))
(if pred (list var pred)
(list var))))
(atom (list arg))))
(remove-if
(lambda (arg)
(member arg '(&key &rest)))
lambda-list))))
nil) ;;;<<<<----- here i am not using any of lambda-list
(dispatch pap-function args))))
CL-USER 5 > (pprint (macroexpand '(def-pap-fun test (a b &key ((:c x) 10 used))
nil)))
(LET ((PAP-FUNCTION
(MAKE-INSTANCE 'PAP-FUNCTION
:NAME
'TEST
:LAMBDA-LIST
'(A B &KEY ((:C X) 10 USED)))))
(ADD-PAP TEST (A B &KEY ((:C X) 10 USED)) T NIL)
(DEFUN TEST (&REST ARGS)
(DESTRUCTURING-BIND (A B &KEY ((:C X) 10 USED)) ARGS
(DECLARE (IGNORABLE A B X USED))
NIL)
(DISPATCH PAP-FUNCTION ARGS)))
CL-USER 6 >