[5] USER(21): (defnode t0 :yes (defnode t1) :no (defnode t2)) Error: keyword list ((DEFNODE T1) :NO (DEFNODE T2)) is not an even number of items [condition type: PROGRAM-ERROR]
I just can't seem to figure. Is there something strange about &optional and/or &key arguments in macros? I'm lost here.
Basically, what I think might be happening is that if I define a function like:
(defun f (x &optional y &key k1 k2) (..))
and then call it like this:
(f 10 :k1 3 :k2 4)
then the &optional argument `y' gets the keyword value `:k1', and I somehow don't agree that this is how it should be, though I can also see how this is a subtle point, where someone had to make a decision.
So, the question is how do be able to pass the args the way I did, such that it still works.
* David Bakhash | Basically, what I think might be happening is that if I define a | function like: | | (defun f (x &optional y &key k1 k2) | (..)) | | and then call it like this: | | (f 10 :k1 3 :k2 4) | | then the &optional argument `y' gets the keyword value `:k1', and I | somehow don't agree that this is how it should be, though I can also | see how this is a subtle point, where someone had to make a decision.
you cannot disallow passing the keyword :K1 to the optional argument Y via the standard argument-parsing machinery, which also cannot force the argument list to match keywords at particular positions, such as ending in a keyword plist. for the whole story on the ordinary lambda list: http://www.harlequin.com/education/books/HyperSpec/Body/sec_3-4-1.html
| So, the question is how do be able to pass the args the way I did, | such that it still works.
taking the easy way out and disallowing keywords as values of optional arguments, which is not a brilliant solution, this could be a start.
Erik Naggum <c...@naggum.no> writes: > taking the easy way out and disallowing keywords as values of optional > arguments, which is not a brilliant solution, this could be a start.
Erik Naggum <c...@naggum.no> writes: > * David Bakhash > | Basically, what I think might be happening is that if I define a > | function like: > | > | (defun f (x &optional y &key k1 k2) > | (..)) > | > | and then call it like this: > | > | (f 10 :k1 3 :k2 4) > | > | then the &optional argument `y' gets the keyword value `:k1', and I > | somehow don't agree that this is how it should be, though I can also > | see how this is a subtle point, where someone had to make a decision.
> you cannot disallow passing the keyword :K1 to the optional argument Y > via the standard argument-parsing machinery, which also cannot force the > argument list to match keywords at particular positions, such as ending > in a keyword plist. for the whole story on the ordinary lambda list: > http://www.harlequin.com/education/books/HyperSpec/Body/sec_3-4-1.html
I was able to get passed this by doing the following, MUCH simpler trick. basically, I used &rest instead of &optional and it works, oddly enough:
and no destructuring-bind needed. I guess &rest and &optional read parameters differently. Anyway, just wanted to let you know. It took me a while to figure that out, and I only got there by trial-and-error.
* David Bakhash | is there some significance to the dot `.' before and after the | `arguments'? i.e. what are the dots for?
to me, such dots communicate "internal use". in a macro, you would typically have used an uninterned symbol to avoid problems, except that this would make the argument list less than useful. "&rest .arguments." at least says something moderately useful.
(remember that all characters can be part of symbol names, and that people adopt many conventions to deal with cognitive overload. *foo* for specials is a pretty solid convention, many use +foo+ for constants, some use .foo. for internal use, I used class names like <foo> for a while, and perhaps there are some even less widely used conventions. :)
#:Erik -- "Where do you want to go to jail today?" -- U.S. Department of Justice Windows 98 slogan
> I was able to get passed this by doing the following, MUCH simpler > trick. basically, I used &rest instead of &optional and it works, > oddly enough:
I thought of this too, but it's not correct. If you supply a value for Y, then Lisp's attempt to extract the keyword arguments gets an error (at least, it does in ACL 4.3, and I believe this is correct behavior). The problem is that Lisp expects the entire &REST argument to be of the form (keyword value ...), but it has the value for Y on the front of it. E.g.:
[1] (f 3 4 :k2 5)
Error: &key list isn't even: (4 :K2 5)
Erik is right: there really can't be a solution to this problem that doesn't require you to provide the information that symbols :K1 and :K2 are not acceptable values for Y. Lisp can't assume that on its own.
-- Scott
* * * * *
To use the email address, remove all occurrences of the letter "q".
* David Bakhash | I was able to get passed this by doing the following, MUCH simpler trick. | basically, I used &rest instead of &optional and it works, oddly enough: | | (defmacro f (x &rest y-list &key k1 k2 &aux (y (first y-list))) | (...)) | | and no destructuring-bind needed. I guess &rest and &optional read | parameters differently. Anyway, just wanted to let you know. It took me | a while to figure that out, and I only got there by trial-and-error.
this shouldn't work. (f 1 2 :k1 3 :k2 4) should signal an error because the number of elements in the list (2 :k1 3 :k2 4) is not a valid plist, i.e., does not have an even number of elements, as per the definition of &REST with &KEY. (f 1 :k1 2 :k2 3) should bind Y to :K1. Allegro CL 4.3, 4.3.1, and 5.0 concur. I wonder how you determined that it works.
you're _much_ better off reading and understanding the standard (or any language specification) than spending time on random stabs in any problem space -- you'll never know what you hit, nor whether you hit something by accident or by design. worse, more often than not what happens to "work" is a special case. please see the HyperSpec. if it's too hard to read, you need to back off and realize that you shouldn't try to solve the problem at hand until you understand what you're doing. you'll get all the help you need here in comp.lang.lisp if you want to understand the language (I know I have benefited thusly) instead of just randomly trying something and then get yourself in need of help when you're confused. more often than not, some minor expectation can block understanding and lead you down weird paths (it has happened to me several times), and the further you go down that path, especially with code you don't understand why doesn't work, the harder it is to recover where you came from and give you the guidance you need to choose the right path.
#:Erik -- "Where do you want to go to jail today?" -- U.S. Department of Justice Windows 98 slogan
* David Bakhash | I was able to get passed this by doing the following, MUCH simpler trick. | basically, I used &rest instead of &optional and it works, oddly enough: | | (defmacro f (x &rest y-list &key k1 k2 &aux (y (first y-list))) | (...)) | | and no destructuring-bind needed. I guess &rest and &optional read | parameters differently. Anyway, just wanted to let you know. It took me | a while to figure that out, and I only got there by trial-and-error.
this shouldn't work. (f 1 2 :k1 3 :k2 4) should signal an error because the resulting rest list (2 :k1 3 :k2 4) is not a valid plist, i.e., it does not have an even number of elements, as per the definition of &REST with &KEY. (f 1 :k1 2 :k2 3) should bind Y to :K1. Allegro CL 4.3, 4.3.1, and 5.0 concur. I wonder how you determined that it works.
you're _much_ better off reading and understanding the standard (or any language specification) than spending time on random stabs in any problem space -- you'll never know what you hit, nor whether you hit something by accident or by design. worse, more often than not what happens to "work" is a special case. please see the HyperSpec. if it's too hard to read, you need to back off and realize that you shouldn't try to solve the problem at hand until you understand what you're doing. you'll get all the help you need here in comp.lang.lisp if you want to understand the language (I know I have benefited thusly) instead of just randomly trying something and then get yourself in need of help when you're confused. more often than not, some minor expectation can block understanding and lead you down weird paths (it has happened to me several times), and the further you go down that path, especially with code you don't understand why doesn't work, the harder it is to recover where you came from and give you the guidance you need to choose the right path.
#:Erik -- "Where do you want to go to jail today?" -- U.S. Department of Justice Windows 98 slogan
Erik Naggum <c...@naggum.no> writes: > more often than not, some minor expectation can block understanding and > lead you down weird paths (it has happened to me several times), and the > further you go down that path, especially with code you don't understand > why doesn't work, the harder it is to recover where you came from and > give you the guidance you need to choose the right path.
yeah. I didn't check all the case; only a couple, and they worked. So I will avoid this and stay away from using &optional/&rest together with &key. safest bet is that if you're gonna use &key, then any other args should be required (in my opinion) except &aux (maybe).
In article <cxj7m31yw7b....@raven.bu.edu>, David Bakhash <ca...@bu.edu> wrote:
>yeah. I didn't check all the case; only a couple, and they worked. >So I will avoid this and stay away from using &optional/&rest together >with &key. safest bet is that if you're gonna use &key, then any >other args should be required (in my opinion) except &aux (maybe).
Yes, this is generally recommended. Common Lisp itself promotes bad practice due to the interface to the READ-FROM-STRING function. It was apparently done the way it was done in order to be consistent with both READ (which uses optional arguments) and the string and sequence functions (which generally use :START and :END). In retrospect, this was a horrible decision, and one of the FAQs that prompted creation of the c.l.lisp FAQ posting was "Why does (read-from-string "a b" :start 2) return A rather than B?"
-- Barry Margolin, bar...@bbnplanet.com GTE Internetworking, Powered by BBN, Cambridge, MA *** DON'T SEND TECHNICAL QUESTIONS DIRECTLY TO ME, post them to newsgroups.
>[5] USER(21): (defnode t0 > :yes (defnode t1) > :no (defnode t2)) >Error: keyword list ((DEFNODE T1) :NO (DEFNODE T2)) is not an even number of items > [condition type: PROGRAM-ERROR]
In addition to the &optional/&key issue being discussed, you should also realize that your macro will multiply evaluate the arguments 'yes' and 'no', which is certainly not what you want. Also, expanding a defining macro into a 'setq' is a dubious choice - I would have used another defining form or even better create your own namespace for nodes in a top-level hash table. Something like this (excuse any non-CL names/arg positions but you should get the idea):
In general, the less you put in a macro and the more you put in runtime support, the better off you are. Exceptions are pretty rare and usually performance-oriented hacks in special cases.
> I was able to get passed this by doing the following, MUCH simpler > trick. basically, I used &rest instead of &optional and it works, > oddly enough:
> and no destructuring-bind needed. I guess &rest and &optional read > parameters differently. Anyway, just wanted to let you know. It took > me a while to figure that out, and I only got there by > trial-and-error.
The macro F doesn't really allow you to have an optional argument, because if you ever called it like:
(f 10 20 :k1 2)
Then the keyword processing would be messed up and an error generated because 20 is not a keyword.
You just changed the case in which an error would occur. Also, the value of y in legal calls to F will always be one of NIL, :K1 or :K2. That is because
This doesn't accept the same argument list as your original example: (defmacro f' (x &optional y &key k1 k2) (...))
The moral of the story is that mixing optional and keyword arguments is not something that is supported by the ANSI-CL standard in the way that would like. As a general rule, you should either use optional arguments or keyword arguments, but mixing them often leads to trouble.
(cf. read-from-string: If you want to read from a string starting somewhere other than the beginning of the string you need to specify the optional error-p and eof-marker arguments before you are allowed to use the :start keyword.)
-- Thomas A. Russ, USC/Information Sciences Institute t...@isi.edu
"Harley Davis" <davis@ilog_dot_com.foo> writes: > In addition to the &optional/&key issue being discussed, you should also > realize that your macro will multiply evaluate the arguments 'yes' and 'no', > which is certainly not what you want. Also, expanding a defining macro into > a 'setq' is a dubious choice - I would have used another defining form or > even better create your own namespace for nodes in a top-level hash table. > Something like this (excuse any non-CL names/arg positions but you should > get the idea):
> ;;; Runtime portion
I don't know how to thank you for all this help, except to say thanks.