lately, I have been annoyed by a what I think is a limitation in the
usability of multiple values. in particular, I need to know whether I
got a NIL back as a value or didn't get anything. MULTIPLE-VALUE-BIND is
insufficient in keeping track of the number of values involed. in my
view, it is as much an error for a function to return too few or too many
values as it was to pass it the wrong number of arguments -- when those
values are actually needed.
now I wonder -- why was MULTIPLE-VALUE-BIND defined so simplistically?
with just a list of symbols to be bound, it sort of defeats the purpose
of a variable number of returned values, doesn't it?
I can obtain the desired behavior with either of these macros (except
that MULTIPLE-VALUE-DESTRUCTURING-BIND is a bad name):
(defmacro multiple-value-destructuring-bind (lambda-list value-form &body body)
`(destructuring-bind ,lambda-list (multiple-value-list ,value-form)
,@body))
(defmacro multiple-value-destructuring-bind (lambda-list value-form &body body)
`(multiple-value-call (lambda ,lambda-list ,@body) ,value-form))
these are fairly expensive when the function receiving multiple values
from some other function _already_ knows how many values it receives and
could signal an error when the number doesn't match expectations.
is there a better way to check the number of returned values than with
MULTIPLE-VALUE-CALL, or is that the only special operator of consequence?
#:Erik
--
God grant me serenity to accept the code I cannot change,
courage to change the code I can, and wisdom to know the difference.
In short I'd say that the list of variables in MULTIPLE-VALUE-BIND is
just that a list of variables. It isn't a lambda list...... nor
was it intended to be a lambda list.
In article <················@naggum.no>, Erik Naggum <······@naggum.no> wrote:
> insufficient in keeping track of the number of values involed. in my
> view, it is as much an error for a function to return too few or too many
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
> values as it was to pass it the wrong number of arguments -- when those
> values are actually needed.
>
> now I wonder -- why was MULTIPLE-VALUE-BIND defined so simplistically?
> with just a list of symbols to be bound, it sort of defeats the purpose
> of a variable number of returned values, doesn't it?
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
In many places in Common Lisp, semantics is to try to
"fail gracefully" in certain circumstances. For instance:
(cond ) ==> NIL
Shouldn't that be an error???? There are no conditions to select...
doesn't that mean something is remiss?
I think MULTIPLE-VALUE-BIND was designed to be used in the
context that the total number of "interesting" return values are known.
It "fails gracefully" when the "values-form" doesn't supply
enough. If it should be strict then it should signal an error, period.
You can do one or the other.
[ "interesting" return values meaning that you can skip those values
you're not interested in getting if they appear at the end.
So it isn't quite following the notion of having to match the
exact number. ]
Here nil should distinguish as the value was unset (or doesn't matter).
NIL is ambiguous or if there is a need to count the return values that
is not the context in which the contruct is applicable.
You'll probably have to use the other appoarches outlined in the macros.
Not every Common Lisp construct has to be infinitely applicable in
all situations. :-)
If you make the "vars" take on the form of an optional lambda list
you can clutter up the syntax.
(new-multiple-value-bind ( a (b nil b-supplied-p) c ) value-form ...)
so it isn't just a list of variables to be bound anymore. And you
have supplied a default value if you want to provide a supplied
parameter. Why are variables being bound to value being given
default values??? I know... there are really being used as the
lambda list to multiple-value-call... but why utilize the
"syntactical sugar" of multiple-value-bind if you force that
realization upon the user....
> these are fairly expensive when the function receiving multiple values
> from some other function _already_ knows how many values it receives and
> could signal an error when the number doesn't match expectations.
How can a function "already" know? There is no restrictions placed
upon the values form. It could be any expression.
> is there a better way to check the number of returned values than with
> MULTIPLE-VALUE-CALL, or is that the only special operator of consequence?
In three of the environments I tried the following example in utilized
mutliple-value-call in the expansion of multiple-value-bind....
However, one did the following....
> ( pprint (macroexpand-1
'(mutiple-value-bind ( a b c) (values 1 2 3 )
a)))
(LET* ((#:VALUES96 (MULTIPLE-VALUE-LIST (VALUES 1 2 3 )))
( A ( POP #:VALUES96) )
( B ( POP #:VALUES96) )
( C ( POP #:VALUES96) ))
A)
>
I'm not so sure I'm happy with this. However, if the list of vars
were some sort of lambda list you couldn't expand in this fashion.
I presume there is some rationale for doing it this way...
However, this does lend itself to the approach of a fixed list
of return values.... by just comparing two lengths...
(defmacro fixed-length-mulitiple-value-bind
( var-list value-form &body body )
"Bind the variable in the var-list to the values returned by the
value form. If the number of return arguments do not match
the number of args signal an error."
(let ( (num-vars (length var-list))
(values-list-symbol (gensym "values")) )
(labels ( (var-bindings ( vars )
(if vars
(cons `( ,(first vars)
(pop ,values-list-symbol ))
(var-bindings (rest vars))))))
`(let ( ( ,values-list-symbol
(multiple-value-list ,value-form )))
(unless (= ,num-vars (length ,values-list-symbol))
(error "not enough values returned" ))
(let* ( ,@(var-bindings var-list ) )
,@body )))))
A tad bit longer than the originally presented macros but is rather
rigid about number of return arguments and I don't have to insert
code into the body to do the checking...
--
Lyman S. Taylor "Because no matter where you go,
(·····@cc.gatech.edu) there you are."
Buckaroo Banzai
In article <··········@pravda.cc.gatech.edu>,
Lyman S. Taylor <·····@cc.gatech.edu> wrote:
P.S.
> In short ....
I think of MULTIPLE-VALUE-BIND in the same light as LET.
Is LET deficient?
( let ( a )
a ;; <- is NIL. Because the init form returned NIL or
;; because there was not init form.
)
...
> However, one did the following....
>
> > ( pprint (macroexpand-1
> '(mutiple-value-bind ( a b c) (values 1 2 3 )
> a)))
>
> (LET* ((#:VALUES96 (MULTIPLE-VALUE-LIST (VALUES 1 2 3 )))
I forgot to mention that this was LispWorks for Windows 4 to
give credit/blame ( depending on your viewpoint) were it is due. :-)
[ Which is interesting because 3.2.2 for SunOS used multiple-value-call]
I guess it is a tradeoff between a lambda invocation that takes all
optional args ( likely to form a list of some sort) and directly
forming a list of the results.
--
Lyman S. Taylor "Because no matter where you go,
(·····@cc.gatech.edu) there you are."
Buckaroo Banzai
In article <··········@pravda.cc.gatech.edu>,
Lyman S. Taylor <·····@cc.gatech.edu> wrote:
...
>
> (defmacro fixed-length-mulitiple-value-bind
after some more thought... the following is slightly less rigid
and has a more tractable name. :-)
(defmacro bind-n-values (num-var var-list value-form &body body)
"Bind the variables in the var-list to the values returned by the
value form. The actual number of values returned by the value-form
is bound to the first argument. Like the variables, this one
is lexically scoped to the body of the construct."
(let ( (num-vars (length var-list))
(values-list-symbol (gensym "values")) )
(labels ( (var-bindings ( vars )
(if vars
(cons `( ,(first vars)
(pop ,values-list-symbol ))
(var-bindings (rest vars))))))
`(let ( ( ,values-list-symbol
(multiple-value-list ,value-form )))
(let* ( ( ,num-var (length ,values-list-symbol))
,@(var-bindings var-list ) )
,@body )))))
This way one can decide just how big of an error this is.....
with necessarily introducing symbols to signify whether
a variable as been bound ( as opposed to only invoking
error is they're not exaclty equal... )
Usage:
> (bind-n-values num (a b c ) (values 1 2 3 )
(format t "~A ~A ~A ~A ~A" a b c num))
1 2 3 3
NIL
> (bind-n-values num (a b c ) (values 1 2 )
(format t "~A ~A ~A ~A ~A" a b c num))
1 2 NIL 2
NIL
> (bind-n-values num (a b c ) (values 1 2 3 4 5)
(format t "~A ~A ~A ~A ~A" a b c num))
1 2 3 5
NIL
>
--
Lyman S. Taylor "Twinkie Cream; food of the Gods"
(·····@cc.gatech.edu) Jarod, "The Pretender"
From: Erik Naggum
Subject: Re: lambda list in MULTIPLE-VALUE-BIND?
Date:
Message-ID: <3098340336248874@naggum.no>
* ·····@cc.gatech.edu (Lyman S. Taylor)
| In short I'd say that the list of variables in MULTIPLE-VALUE-BIND is
| just that a list of variables. It isn't a lambda list...... nor was it
| intended to be a lambda list.
sigh. I _know_ that, dammit. the question is _why_.
| How can a function "already" know? There is no restrictions placed upon
| the values form. It could be any expression.
sigh. when a function returns a number of values, the receiving code
(remember? there's actually a computer underneath here) _knows_ at that
time how many values it received. it isn't constant, if that's what you
think, but it _has_ to know, one way or the other, because it will take
actions that depend on such knowledge, like binding variables with no
corresponding value to NIL. if it had no clue how many values it
received, it couldn't do that, OK? so when it already has that value, I
want to cause an error if it is not the number I expect, _without_ having
to engage in very expensive operations or cons up the values into a list
-- I might just as well return a list, then, were it not for the fact
that I do need the distinction between the primary value and the
non-primary values in other contexts.
| In three of the environments I tried the following example in utilized
| mutliple-value-call in the expansion of multiple-value-bind.... However,
| one did the following....
the compiler is not obliged to do the same kind of macroexpansion as you
are. you have to look at the compiled code or know your compiler better
to understand how it does its work. compiler-macros do weird stuff.
but aren't you aware that DESTRUCTURING-BIND will barf on the wrong
number of bound variables already? there's no need to reinvent it.
#:Erik
--
God grant me serenity to accept the code I cannot change,
courage to change the code I can, and wisdom to know the difference.
In article <················@naggum.no> Erik Naggum <······@naggum.no> writes:
| How can a function "already" know? There is no restrictions placed upon
| the values form. It could be any expression.
sigh. when a function returns a number of values, the receiving code
(remember? there's actually a computer underneath here) _knows_ at that
time how many values it received. it isn't constant, if that's what you
think, but it _has_ to know, one way or the other, because it will take
actions that depend on such knowledge, like binding variables with no
corresponding value to NIL. if it had no clue how many values it
received, it couldn't do that, OK? so when it already has that value, I
^^^^^^^^^^^^^^^^^^^^^^^
A rather strong claim! I could propose a mechanism by which the system
would not really *count* the number of arguments received. All the system
needs to have is a list of the symbols to be bound, and some way to
differentiate a frame from a return value on the stack. Then, it could pop
values one at a time off the stack, and bind them to the next available
variable.
want to cause an error if it is not the number I expect, _without_ having
to engage in very expensive operations or cons up the values into a list
-- I might just as well return a list, then, were it not for the fact
that I do need the distinction between the primary value and the
non-primary values in other contexts.
I'm afraid you might be stuck with multiple-value-call... This is the best
I could come up with... (which looking back on your original post is
exactly what you had come up with)
(defmacro fixed-length-multiple-value-bind (vars values-form &rest body)
`(multiple-value-call #'(lambda ,vars ,@body) ,values-form))
One way around the efficiency issue is by using the above macro only for
debugging, and using regular multiple-value-bind when you have your program
straightened out.
Sunil
In article <················@naggum.no>, Erik Naggum <······@naggum.no> wrote:
>* ·····@cc.gatech.edu (Lyman S. Taylor)
...
>| intended to be a lambda list.
>
> sigh. I _know_ that, dammit. the question is _why_.
A suitable answer is "why not". It is a programming design choice.
I don't see conclusive agrument for why it should have to be a lambda list.
As I stated in one of my follow ups a list of variable names matches
well with LET. LET doesn't have all the optional lambda list constructs.
>
>| How can a function "already" know? There is no restrictions placed upon
>| the values form. It could be any expression.
>
> sigh. when a function returns a number of values, the receiving code
sigh. I was speaking of speaking at the source code level. Since,
the discussion was about common lisp the language and not common
lisp the implementation. I suppose I should have said how can the
programmer know.
There is no way in common lisp to directly retrieve this number.
Therefore, the code (the function) can't reflect knowledge about what
this number is.
If that is your complaint then perhaps there is an argument
for something that would make this number more directly
accessible at the source code level. However, that does NOT
necessitate giving optional lambda list semantics to binding
the multiple values.
What if there were something like (values-and-n .... )
> (values-and-n 'a "b" #\c )
3
A
"b"
#\c
>
Granted optional argument lambda lists have the same sort of
problem ( how many got bound), but doesn't mean that the same
solution need be applied.
If the concept of "either it is the right number or it is wrong"
is being applied, the crux of the problem is "how many" not
"which ones".
>
>| In three of the environments I tried the following example in utilized
>| mutliple-value-call in the expansion of multiple-value-bind.... However,
>| one did the following....
>
> the compiler is not obliged to do the same kind of macroexpansion as you
> are. you have to look at the compiled code or know your compiler better
> to understand how it does its work. compiler-macros do weird stuff.
The point of my ilustration was that there was another approach
to solving the problem that fits the current syntax than those
you presented. If you propose changing the syntax you'd disallow
this approach [ yet another reason why the designer may have chosen
this syntax. ]
I would expect that a good really compiler might recognize that the
resulting list has a very brief lifetime and simply forgo consing up
the list. Which would require no magical compiler macro to do the
job at all. I would suspect that a vendor would write macros
that expanded into idioms that they their compiler works well with.
So looking at the compiler results would seem rather inconclusive
whether a different expansion is delivered to the compiler or the compiler
just did a good job.
> but aren't you aware that DESTRUCTURING-BIND will barf on the wrong
> number of bound variables already? there's no need to reinvent it.
Sure, I get some wierd error message from DESTRUCTING-BIND... Personally
I try to present informative error messages in my code. I spend
portion of my time as a TA explaining what errors messages
typically presented by most common lisp enviroments mean in English.
Especially in this context, the DESTRUCTING-BIND will not be
present in the original source.
Perhaps a personal coding style quirk I guess. ;-)
Seemingly, you have already picked out your "hammer" and are looking
for support in labeling the problem as a "nail". I don't think it is
a "nail" and you don't need the "hammer". However, I wasn't on
committee that designed multiple-value-bind. My intuition says that
someone had the thought of constructing something like LET for
capturing mutliple values. Hence, multiple-value-bind looks like
it does. But that is just my intuition.
In most cases the construct works and isn't a problem. For situations
which require more the more "low level" constructs are there and
"roll your own". Like I said before every construct need not be
universally applicable in all contexts. Gee, you have two solution
macros that require one line to compose...
I also think that filling up of the body of the construct with code
testing supplied-p variables when primarily what I want to know is
how many values got returned isn't the best approach.
--
Lyman S. Taylor "Twinkie Cream; food of the Gods"
(·····@cc.gatech.edu) Jarod, "The Pretender"