From: Vassil Nikolov
Subject: binding multiple values (Ex: Re: some small proposed changes to standard)
Date: 
Message-ID: <l03130302b3bcfc3f6752@195.138.129.78>
Mark Stickel wrote:                [1999-07-20 21:20 -0700]
(to the ·····@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: ········@poboxes.com
For more: http://www.poboxes.com/vnikolov
  Abaci lignei --- programmatici ferrei.

From: Erik Naggum
Subject: Re: binding multiple values (Ex: Re: some small proposed  changes to standard)
Date: 
Message-ID: <3141799301028302@naggum.no>
* Vassil Nikolov <········@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?
From: Kent M Pitman
Subject: Re: binding multiple values (Ex: Re: some small proposed  changes to standard)
Date: 
Message-ID: <sfwbtd2rtir.fsf@world.std.com>
Erik Naggum <····@naggum.no> writes:

> * Vassil Nikolov <········@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.
From: Erik Naggum
Subject: Re: binding multiple values (Ex: Re: some small proposed  changes to standard)
Date: 
Message-ID: <3141905649180895@naggum.no>
* Kent M Pitman <······@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.

#:Erik
-- 
  suppose we blasted all politicians into space.
  would the SETI project find even one of them?
From: Fernando Mato Mira
Subject: Re: binding multiple values (Ex: Re: some small proposed  changes to  standard)
Date: 
Message-ID: <379B74DB.687319F0@iname.com>
Erik Naggum wrote:

> * Kent M Pitman <······@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.
From: Fernando Mato Mira
Subject: Re: binding multiple values (Ex: Re: some small proposed  changes to  standard)
Date: 
Message-ID: <379B7CDF.58DA7F83@iname.com>
Fernando Mato Mira wrote:

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

                 ^^^^^

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

duh.
From: Fernando Mato Mira
Subject: Re: binding multiple values (Ex: Re: some small proposed  changes to  standard)
Date: 
Message-ID: <379B75CC.CAF016F5@iname.com>
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))

;-)
From: Kent M Pitman
Subject: Re: binding multiple values (Ex: Re: some small proposed  changes to standard)
Date: 
Message-ID: <sfw1zdwqwy6.fsf@world.std.com>
Erik Naggum <····@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.