Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

binding multiple values (Ex: Re: some small proposed changes to standard)

10 views
Skip to first unread message

Vassil Nikolov

unread,
Jul 22, 1999, 3:00:00 AM7/22/99
to comp.la...@list.deja.com
Mark Stickel wrote: [1999-07-20 21:20 -0700]
(to the x3...@ai.sri.com list)

Among other items:

> 4. Add multiple-value-binding capability to LET, LET*, DO, DO*
>
> Multiple value binding is useful, but is poorly integrated syntactically
> with the rest of Common Lisp. In LET, LET*, DO, DO* binding forms
> (var value) or (var value next-value), allow (var1 ... varn) instead
> of var to bind multiple values returned by the value and next-value
> forms. Multiple value binding can be more succinctly expressed with
> less indentation this way, e.g.,
> (let* ((x value1)
> ((u v) values2)
> (y value3))
> ...)
> versus
> (let ((x value1))
> (multiple-value-bind (u v) values2
> (let ((y value3))
> ...)))
> Moreover, binding in parallel becomes easy to specify, as in
> (let ((x value1)
> ((u v) values2)
> (y value3))
> ...)
> Problem: this might be confused with destructuring in
> destructuring-bind and macro argument lists that has similar
> purpose and different behavior (e.g., what is done with
> extra or unsupplied values).

If the syntax of binding forms is to be extended (which appears
a good idea to me), then perhaps it could be extended in another
way as well. In a recent post, Fernando Mato Mira (I think)
suggested that the above syntax is incompatible with the
(hypothetical) desire to have the type alongside the variable:

(let (((i integer) 0))
...)
->
(let ((i 0))
(declare (type integer i))
...)

I propose to have the two coexist with the syntax

(LET ((({var [:TYPE type]}+) values-form))
body)

e.g.

(let (((q :type integer r :type integer) (floor a b)))
...)

This is similar to declaring the type of structure components.

As to the problem noted above---confusion with destructuring---
I think I can live with that because destructuring does not deal
with multiple values and I can keep the two cases distinct in
my head.


Vassil Nikolov
Permanent forwarding e-mail: vnik...@poboxes.com
For more: http://www.poboxes.com/vnikolov
Abaci lignei --- programmatici ferrei.

Erik Naggum

unread,
Jul 24, 1999, 3:00:00 AM7/24/99
to
* Vassil Nikolov <vnik...@poboxes.com>

| If the syntax of binding forms is to be extended (which appears a good
| idea to me), then perhaps it could be extended in another way as well.
| In a recent post, Fernando Mato Mira (I think) suggested that the above
| syntax is incompatible with the (hypothetical) desire to have the type
| alongside the variable:

since LET binding forms are to take a variable and a form, I don't see
the need to stuff the type in with the variable. since type information
is optional, let's use the standard way to specify optional stuff: add it
at the end:

(let ((i 0 integer)) ...)

(do ((i 0 (1+ i) integer)) ...)

and with multiple-value extensions:

(let (((q r) (floor a b) (integer integer))) ...)

#:Erik
--
suppose we blasted all politicians into space.
would the SETI project find even one of them?

Kent M Pitman

unread,
Jul 24, 1999, 3:00:00 AM7/24/99
to
Erik Naggum <er...@naggum.no> writes:

> * Vassil Nikolov <vnik...@poboxes.com>
> | If the syntax of binding forms is to be extended (which appears a good
> | idea to me), then perhaps it could be extended in another way as well.
> | In a recent post, Fernando Mato Mira (I think) suggested that the above
> | syntax is incompatible with the (hypothetical) desire to have the type
> | alongside the variable:
>
> since LET binding forms are to take a variable and a form, I don't see
> the need to stuff the type in with the variable. since type information
> is optional, let's use the standard way to specify optional stuff: add it
> at the end:
>
> (let ((i 0 integer)) ...)
>
> (do ((i 0 (1+ i) integer)) ...)
>
> and with multiple-value extensions:
>
> (let (((q r) (floor a b) (integer integer))) ...)

Because of the prevalance of variables named things like INTEGER, etc.
this is probably not adequately good for error checking. The DO and
LET above might be typos for ill-formed lets that might not get caught.
Might be better to require a stronger boundary, like
(let ((i 0 :type integer)) ...)

Although there are other reasons why

(let (((the integer i) ...)) ...)

would be simplest. Or

(let (((the (values integer integer) (values x y)) (window-pos))) ...)

I'm mostly not following this thread of the conversation, but figured
I'd peek in. Sorry if someone's already suggested this.

Erik Naggum

unread,
Jul 25, 1999, 3:00:00 AM7/25/99
to
* Kent M Pitman <pit...@world.std.com>

| Because of the prevalance of variables named things like INTEGER, etc.
| this is probably not adequately good for error checking. The DO and
| LET above might be typos for ill-formed lets that might not get caught.

although I find the reasoning puzzling, using a keyword to specify type
seems like a good idea to me because we might want to add other optional
declarations, as in

(let ((foo () :type list :dynamic-extent t))
...)

| Although there are other reasons why
|
| (let (((the integer i) ...)) ...)
|
| would be simplest.

the symmetry with how it would be written in the absence of declarations
is appealing, but although I favored this form myself previously, they
"bury" the variables that are being bound in a lot of clutter, making it
hard to locate what is being bound. if your reasoning above is valid, it
appears to be more cause for concern for typos and problems with this
approach than the one above.

Fernando Mato Mira

unread,
Jul 25, 1999, 3:00:00 AM7/25/99
to
Erik Naggum wrote:

> * Kent M Pitman <pit...@world.std.com>
> | Because of the prevalance of variables named things like INTEGER, etc.
> | this is probably not adequately good for error checking. The DO and
> | LET above might be typos for ill-formed lets that might not get caught.
>
> although I find the reasoning puzzling, using a keyword to specify type
> seems like a good idea to me because we might want to add other optional
> declarations, as in

If the aim is to get rid of DECLARES, one might as well go the whole way,
and avoid all that keywordy stuff (my yuck).

After all that LETBIND discussion, I've personally came to the conclusion
that the best way is (regardless of whether there's only one form, LET,
or two, LET and MULTIPLE-VALUE-LET).

Remember, CMUCL will give you an error if a declared numeric variable
has not initializer, so not being able to specify the type of an uninitialized
variable is not a big loss in my opinion (use 0s or NILs).
[
(MULTIPLE-VALUE-LET
( var | varlist | ({var | varlist} [initializer decls*])*)
...)

where decls will just expand to (DECLARE decls*) except for the following
conveniences:

if a decl is a symbol, it will apply to all variables in varlist.

Otherwise, if decl does not contain at least one of the variables in varlist,
it
is also applies to all variables in varlist
[for type declarations, one could add `that have no type specifically
assigned']

decls that do not start with one of the declaration identifiers
[
declaration ignore special
dynamic-extent inline type
ftype notinline
ignorable optimize
]
will be assumed to be type declarations.

Also, if initializer is an atom, it applies to all the variables in varlist.

So, for example:

(MULTIPLE-VALUE-LET
(((x y) 0.0 double-float)
((u v) #(1 0) ((vector fixnum)))
((o p) NIL standard-object dynamic-extent)
((a l w) (foo) (float a) ((vector single-float) w) (dynamic-extent l))
...)

If you want to have a type called `DYNAMIC-EXTENT' or something like that,
use DECLARE, that's your fault.


Fernando Mato Mira

unread,
Jul 25, 1999, 3:00:00 AM7/25/99
to
Fernando Mato Mira wrote:

> If you want to have a type called `DYNAMIC-EXTENT' or something like that,
> use DECLARE, that's your fault.

OK. I'll let you do:

((genius nil (type dynamic-extent))

;-)

Kent M Pitman

unread,
Jul 25, 1999, 3:00:00 AM7/25/99
to
Erik Naggum <er...@naggum.no> writes:

> | Although there are other reasons why
> |
> | (let (((the integer i) ...)) ...)
> |
> | would be simplest.
>
> the symmetry with how it would be written in the absence of declarations
> is appealing, but although I favored this form myself previously, they
> "bury" the variables that are being bound in a lot of clutter, making it
> hard to locate what is being bound. if your reasoning above is valid, it
> appears to be more cause for concern for typos and problems with this
> approach than the one above.

We talked about this long ago
in the destructuring discussion. The key reason to have
(letbind (((values x y) (values 3 4)) ..))
instead of
(letbind (((x y) (values 3 4))) ...)
is to allow things other than VALUES to be used. e.g., constructors.
And once you allow
(letbind (((cons a b) (cons 3 4))) ...)
then you might also want abstractions like
(letbind (((make-instance 'foo :a 3 :b 4) (current-foo))) ...)
and you might want that to be implemented by macroexpansion so that
(macrolet ((xcons (x y) `(cons ,x ,y)))
(letbind (((xcons a b) (cons 1 2))) ...))
==>
(letbind (((cons b a) (cons 1 2))) ...)
==>
(let ((b 1) (a 2)) ...)
And if that can be the case, then you might want just
(macrolet ((ivalue (x) `(the integer ,x)))
(letbind (((ivalue z) 3)) ...))
or
(macrolet ((sizes (x y) `(the (values integer integer) (values ,x ,y))))
(letbind (((sizes width height) (window-size foo)))
...))
So burying the type in the part to bind might be useful if the purpose
is to let it ride around invisibly.

I do agree with you the macroexpanded part is cumbersome,
but then so is a LET macroexpanded into a LAMBDA.
Sometimes you put things in the language just to support
nice composition, and I was thinking this might be a good such place.

Before anyone flags me on the issue of macroexpanding here, though,
let me be sure to do some disclaiming right up front:
I admit it's a little weird to say that LET might macroexpand in a
context where the variables are imminently-to-be-bound. That is, in:
(defmacro foo (x) `(the float ,x))
(let ((a 3))
(declare (fixnum a))
(letbind (((foo a) z)) ...))
where A while FOO is playing with it is hanging delicately perched between
two universes. I can't see a "screw case" to this, but I smell one close by.

Fernando Mato Mira

unread,
Jul 25, 1999, 3:00:00 AM7/25/99
to
Fernando Mato Mira wrote:

> (MULTIPLE-VALUE-LET
> ( var | varlist | ({var | varlist} [initializer decls*])*)
> ...)

^^^^^

(MULTIPLE-VALUE-LET
( var | ({var | varlist} [initializer decls*])*)
...)

duh.


0 new messages