From: Marco Antoniotti
Subject: LETBIND (why Tcl is more powerful than CL)
Date: 
Message-ID: <lwwvvszxcv.fsf@copernico.parades.rm.cnr.it>
After having trolled on comp.lang.tcl, the gods decided that my hubris
had to be punished.  And of course, the punishment got directly wher it
hurts most. :}

As you may know, I built two little packages that deal with LET
behavior. LETBIND and VARDEF.  The LETBIND package is kind of nice,
since it (tries) to collapse LET, LET*, MULTIPLE-VALUE-BIND, and
DESTRUCTURING-BIND into a single LETBIND/LETBIND* form.

Well, it turns out that I did not carefully thought out my design and
the following example breaks down (thanks to Mark Stickel for pointing
this out).

(let ((a 1))
  (letbind ((a 2)
            ((b) :values (values a)))
    b))
; ==> 2

The problem is that you would *really* want to have the form return 1.

What is happening is that the inner LETBIND form expands into

	(let ((a 2))
          (multiple-value-bind (b) (values a) b))

You see the problem.

Now it turns out that, in order to get this right you would really
need to access the *outer* environment.

I.e. you would want an expansion of the kind

	(let ((%outer-A-binding% a))
          (let ((a 2))
            (multiple-value-bind (b) (values %outer-A-binding%) b)))

Which means that you'd have to code walk the RHSs and collect all
possible free references to the outer environent, and then establish
all the proper temporaries in the fashion I'd proposed.

It is doable.

But wouldn't have Tcl's [uplevel] and frends worked better? :)

I made an ass of myself, but having to concede the previous sentence
is to put salt in the wound :}

Cheers


-- 
Marco Antoniotti ===========================================
PARADES, Via San Pantaleo 66, I-00186 Rome, ITALY
tel. +39 - 06 68 10 03 17, fax. +39 - 06 68 80 79 26
http://www.parades.rm.cnr.it/~marcoxa

From: Andy Freeman
Subject: Re: LETBIND (why Tcl is more powerful than CL)
Date: 
Message-ID: <7n7i1b$vst$1@nnrp1.deja.com>
In article <··············@copernico.parades.rm.cnr.it>,
  Marco Antoniotti <·······@copernico.parades.rm.cnr.it> wrote:

> (let ((a 1))
>   (letbind ((a 2)
>             ((b) :values (values a)))
>     b))
> ; ==> 2
>
> The problem is that you would *really* want to have the form return 1.
...
> Which means that you'd have to code walk the RHSs and collect all
> possible free references to the outer environent, and then establish
> all the proper temporaries in the fashion I'd proposed.

There's an easier way.  First you bind all of the values to
temporaries, using a convenient nesting of let and multiple-value-bind,
and then you bind all of the vars that you really wanted to
those temporaries.

>(let ((a 1))
>   (letbind ((a 2)
>             ((b) :values (values a)))
>     ...))

the letbind becomes (using t# instead of gensyms)
(let ((t1 2))
  (multiple-value-bind (t2) (values a)
    (let ((a t1)
          (b t2))
      ...)))

BTW - I'm confused why the :values keyword is necessary if you're
using a list to specify the values-receiving variable names.
(I'll bet that there's more to the letbind syntax than shown
above - perhaps it also includes destructuring-bind.)

-andy


Sent via Deja.com http://www.deja.com/
Share what you know. Learn what you don't.
From: Marco Antoniotti
Subject: Re: LETBIND (why Tcl is more powerful than CL)
Date: 
Message-ID: <lwbtd3k8ir.fsf@copernico.parades.rm.cnr.it>
Apart from Fernando's musing :)

Andy Freeman <······@earthlink.net> writes:

> In article <··············@copernico.parades.rm.cnr.it>,
>   Marco Antoniotti <·······@copernico.parades.rm.cnr.it> wrote:
> 
> > (let ((a 1))
> >   (letbind ((a 2)
> >             ((b) :values (values a)))
> >     b))
> > ; ==> 2
> >
> > The problem is that you would *really* want to have the form return 1.
> ...
> > Which means that you'd have to code walk the RHSs and collect all
> > possible free references to the outer environent, and then establish
> > all the proper temporaries in the fashion I'd proposed.
> 
> There's an easier way.  First you bind all of the values to
> temporaries, using a convenient nesting of let and multiple-value-bind,
> and then you bind all of the vars that you really wanted to
> those temporaries.

Yep.  That is the way to do it.  I should have thought of it.

> BTW - I'm confused why the :values keyword is necessary if you're
> using a list to specify the values-receiving variable names.
> (I'll bet that there's more to the letbind syntax than shown
> above - perhaps it also includes destructuring-bind.)


The point of the exercise was to respond to a post on CLL.  The idea
was to collapse LET/LET*, MULTIPLE-VALUE-BIND and DESTRUCTURING-BIND
into a single form while doing the right thing with declarations.

The syntax was a compromise, while retaining CL style.

An alternative would be to have each binding as

  ([:var | :values ] <binding form> <value(s) form> [<decl>*])

I.e.

  (letbind ((:var x (f y))
            (:values (a s d) (values x y z) (fixnum a))
            (:var (head & rest tail) (list 1 2 3))
            (:var zut "Zut!")
           )
	<body>)

With hindsight this is a better design.  When the CADR of a binding
starting with :VAR is a symbol then the form expands into a LET/LET*,
when it is a CONS it expands into DESTRUCTURING-BIND.

But Fernando is right.  All the problems really stem from trying to
include DESTRUCTURING-BIND into this design.  Just doing LET/LET* and
MULTIPLE-VALUE-BIND is more semantically sound an way easier.

Cheers


-- 
Marco Antoniotti ===========================================
PARADES, Via San Pantaleo 66, I-00186 Rome, ITALY
tel. +39 - 06 68 10 03 17, fax. +39 - 06 68 80 79 26
http://www.parades.rm.cnr.it/~marcoxa
From: Fernando Mato Mira
Subject: &rest (was: LETBIND)
Date: 
Message-ID: <379B64A7.82E01B09@iname.com>
Marco Antoniotti wrote:

> But Fernando is right.  All the problems really stem from trying to
> include DESTRUCTURING-BIND into this design.

_Syntactic_ problems, that is.

> Just doing LET/LET* and MULTIPLE-VALUE-BIND is more semantically sound an
> way easier.

Let's make it even `clearer': :)

let ((A 1))
  (letbind ((a (foo))
            (b (bar a))
            ((c d) (baz x))
            ((e f) (values 1 2 3))
            ((g h) (floor a 3))
            ((i) (cl:floor a 2)))
            ((j k l m) (values 1 2 (baz) (froboz))
            ((n o p)
             (values
               1
               (no-side-effects (side-effects (no-side-effects y)))
               3
               (no-side-effects (side-effects (no-side-effects y)))))
            ((q r) :structure (quux))
            ((s u) :structure l))
      ...))

-->

(let ((a 1))
  (multiple-value-call
      (lambda (a b c d e f g h i j k l m n o p #:s1 #:s2)
         (destructuring-bind (q r) #:s1
            (destructuring-bind (s u) #:s2
              ...)))
      (values (foo))
      (values (bar a))
      (multiple-value-bind (c d) (baz x)
                      (values c d))
      (values 1 2)
      (floor a 3) ; provided it's the actual CL:FLOOR, that is
      (values (cl:floor a 2))
      (values 1 2 (baz) (froboz))
      (funcall
         (lambda (o &rest #:dummy)
           (values 1 o 3))
         (no-side-effects (side-effects (no-side-effects y)))
         (side-effects (no-side-effects y)))
      (values (quux))
      l))

Look ma, no hands!

[X3J13 NOTE: make the variable after &rest optional]
From: Fernando Mato Mira
Subject: LET semantics (was: LETBIND)
Date: 
Message-ID: <379C515B.B688CF17@iname.com>
>> Let's make it even `clearer': :)

Obviously, you can do a similar trick for the destructuring variables,
but it has a different flavor (you don't bind the same value to the same
name always). [With that said, I'll use it below]

Now, why does the definition of LET say:

"first evaluates the expressions init-form-1, init-form-2, and so on, in that
order"

That prevents not only evaluating:

(let ((x (values (a) (b)))
      (y (values (c) (d))))

(c) (d) (a) (b)

but, more importantly, concurrency:
(a) (b)
(c) (d)

(a) (c) (b) (d)

etc.

[OK. I can see that you want to ensure code don't need explicit synchronization

"for the future". What's that called? PARLET?]

Now, if that were not the case, it would be consistent for
an implementation of MULTIPLE-VALUE-LET to do as follows (LETBIND
could still go this way on its own, but given that one would
like to write it in terms of the former..):

(let ((A 1))
  (parletbind ((a (foo))
            (b (bar a))
            ((c d) (baz x))
            ((e f) (values 1 2 3))
            ((g h) (floor a 3))
            ((i) (cl:floor a 2)))
            ((j k l m) (values 1 2 (baz) (froboz))
            ((n o p)
             (values
               1
               (no-side-effects (side-effects (no-side-effects y)))
               3
               (no-side-effects (side-effects (no-side-effects y)))))
            ((q r) :structure (quux))
            ((s u) :structure l))
      ...))

-->

(let ((a 1))
  (multiple-value-call
      (lambda (a b c d e f g h i j k l m n o p q s &rest #:dummy)
         (destructuring-bind (q r) q
            (destructuring-bind (s u) s
              ...)))
      (values (foo))
      (values (bar a))
      (multiple-value-bind (c d) (baz x)
                      (values c d))
      (values 1 2)
      (floor a 3) ; provided it's the actual CL:FLOOR, that is
      (values (cl:floor a 2))
      (values 1 2 (baz) (froboz))
      (values 1 (no-side-effects (side-effects (no-side-effects y))) 3)
      (values (quux))
      l
      (side-effects (no-side-effects y))))


[END OF LETBIND STORY, BESIDES OBVIOUS TRANSFORMATIONS
 MULTIPLE-VALUE-[PAR]LET from now on]
From: Kent M Pitman
Subject: Re: LET semantics (was: LETBIND)
Date: 
Message-ID: <sfwvhb7qn2n.fsf@world.std.com>
Fernando Mato Mira <········@iname.com> writes:

> That prevents not only evaluating:
> 
> (let ((x (values (a) (b)))
>       (y (values (c) (d))))
> 
> (c) (d) (a) (b)
> 
> but, more importantly, concurrency:
> (a) (b)
> (c) (d)
> 
> (a) (c) (b) (d)

It is an established (if not well-advertised) lemma of Lisp design
that attempts to worry about concurrency at the language glue level
are misguided.  To really worry about concurrency, you have to do so
many other things to your programs besides merely "allow it to happen"
(including locking, synchronization, worrying that "inconsistent"
results which were not possible without concurrency might happen in
situations where the programmer had thought he'd enumerated the full
space of possibilities--e.g., the interleaving case you cite above,
etc.) that it is just not rational to think of a concurrent language
as a simple fallout of a tiny change to a non-concurrent language.
Concurrency is great, for those who like it, but it has to be designed
in from the ground up, and neither CL nor even Scheme is a candidate
for this, at least with any existing program.  It might be a small
change to the language spec to make it concurrent, I mean, but the
change to programs that use that subtly different language will be
potentially much larger, and no existing program can be assumed to
work just because the change to the language spec was small.
From: Fernando Mato Mira
Subject: Re: LET semantics (was: LETBIND)
Date: 
Message-ID: <379D6F5F.DA7DEE34@iname.com>
Kent M Pitman wrote:

> It is an established (if not well-advertised) lemma of Lisp design
> that attempts to worry about concurrency at the language glue level
> are misguided.  To really worry about concurrency, you have to do so
> many other things to your programs besides merely "allow it to happen"
> (including locking, synchronization, worrying that "inconsistent"
> results which were not possible without concurrency might happen in
> situations where the programmer had thought he'd enumerated the full
> space of possibilities--e.g., the interleaving case you cite above,
> etc.) that it is just not rational to think of a concurrent language
> as a simple fallout of a tiny change to a non-concurrent language.
> Concurrency is great, for those who like it, but it has to be designed
> in from the ground up, and neither CL nor even Scheme is a candidate
> for this, at least with any existing program.  It might be a small
> change to the language spec to make it concurrent, I mean, but the
> change to programs that use that subtly different language will be
> potentially much larger, and no existing program can be assumed to
> work just because the change to the language spec was small.

Sure I would not even think of changing LET. Moreover the semantics do
make sense given that it maps directly into an application,
and the special form is practical when you really want to take advantage
of the sequentiality.

But I think it would be useful to have another version with concurrent
semantics. Not because of thinking parallel implementations would become
so good so soon, but mainly to impose less restrictions to code
transformations in a sequential context.

The constructs I see mentioned in the '89 workshop on parallel Lisp (QLET,
etc.) all seem heavyweight. That is, they
all tell "you'd better spawn a computation here"[maybe predicated],  not
"you _might_ spawn a computation here, if you're really sure about it".

I don't remember ever taking advantage of the sequentiality of the LET
RHSs. I always assumed they could happen in any order (might be some old
Scheme habit of mine). Nobody has ever come with a notation for that? It
costs me nothing to write CLET (or whatever),
and who knows, one day I might be able to leverage that for free.
From: Fernando Mato Mira
Subject: Re: LET semantics (was: LETBIND)
Date: 
Message-ID: <379DB08F.10150B0@iname.com>
Fernando Mato Mira wrote:

> I don't remember ever taking advantage of the sequentiality of the LET
> RHSs. I always assumed they could happen in any order (might be some old
> Scheme habit of mine). Nobody has ever come with a notation for that? It
> costs me nothing to write CLET (or whatever),
> and who knows, one day I might be able to leverage that for free.

I was thinking about this during my lunch break. Actually, one would like to
reserve words for all the combinations that immediately come to one's mind:

LLET (lazy let) - If the values are not used, they don't need to be evaluated
at all.
SLET (lazy, but `strict' let) - All the RHSs will be guaranteed evaluated on
exit from the form.
ELET (eager let) - The above `CLET'.
LET (eager, and sequential let) - What we now have.

Which imply the associated flavors of LAMBDA.

If you want more flexibility than that, you need explicit annotations on
variables/bindings, very much like in Clean.
For example:

-  lazy
+  `strict'
! eager
$ sequential

Then you could do:

(llambda (u $v !w $x !y !z) ...)

Meaning
1. "don't care about u"
2. "if x is needed, v should be done first"
3. "do w, y and z before entering, in whatever order"

(llambda (u $v $!w $x !y !z) ...)
Changing for:
3. "do w first; then y and z in whatever order before entering"

(llambda (u $v !w $x $!y !z) ...)
Changing for:
3. "do y first; then w and z in whatever order before entering"

(llambda (u $v $!w $x $!y !z) ...)
Changing for:
3. "do w; then y; then z `in whatever order' before entering"

Note that:
(llambda (u $v w $+x $y z) ...)
is equivalent to
(llambda (u $+v w $+x $y z) ...)


--
Fernando D. Mato Mira
Real-Time SW Eng & Networking
Advanced Systems Engineering Division
CSEM
Jaquet-Droz 1                   email: matomira AT acm DOT org
CH-2007 Neuchatel                 tel:       +41 (32) 720-5157
Switzerland                       FAX:       +41 (32) 720-5720

www.csem.ch      www.vrai.com     ligwww.epfl.ch/matomira.html
From: Tim Bradshaw
Subject: Re: LETBIND (why Tcl is more powerful than CL)
Date: 
Message-ID: <nkjlnc8vms5.fsf@tfeb.org>
Marco Antoniotti <·······@copernico.parades.rm.cnr.it> writes:

> (let ((a 1))
>   (letbind ((a 2)
>             ((b) :values (values a)))
>     b))
> ; ==> 2
> 

I thought about exactly this -- using the naive approach you end up
with LET* semantics.  You can however get around it by deviousness.

The trick is to work in two stages, the first one with secret variables:

	(let-mv (((a b) (values 1 2))
	      (c a))
	   ...)

expands to something like:

	(multiple-value-bind (#:a #:b) (values 1 2)
	  (let ((#:c a))
            (let ((a #:a) (b #:b) (c #:c))
	      ...)))

I think that this gives you LET semantics as you'd want.  You rely on
the compiler being smart enough to not die due to excessive numbers of
local variables though, and even then it might be hard to generate
really good code for this. So I think there is some argument for just
extending LET to allow the multiple-value syntax, which should be OK
because it can never clash with existing syntax that I can see.  Of
course if you want multiple-values *and* destructuring you're in
trouble, but I never want destructuring so I don't care (:-).

--tim
From: Tim Bradshaw
Subject: Re: LETBIND (why Tcl is more powerful than CL)
Date: 
Message-ID: <ey31ze0e8hn.fsf@lostwithiel.tfeb.org>
* I wrote:

> The trick is to work in two stages, the first one with secret variables:

> 	(let-mv (((a b) (values 1 2))
> 	      (c a))
> 	   ...)

> expands to something like:

> 	(multiple-value-bind (#:a #:b) (values 1 2)
> 	  (let ((#:c a))
>             (let ((a #:a) (b #:b) (c #:c))
> 	      ...)))

And, for what it's worth, here is what I wrote some time ago.  I don't
know if this is actually right -- I tried it momentarily and it seems
to be, but it's not exactly high-quality code...

It doesn't do destructuring or declarations, just multiple values.  It
doesn't particularly check for errors.

The two interesting macros are BIND and BIND*.

--tim

--cut--
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; -*- Mode: Lisp -*- ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; File		     - mvb.lisp
;; Description	     - multiple value binding
;; Author	     - Tim Bradshaw (tfb at lostwithiel.tfeb.org)
;; Created On	     - A long time ago
;; Last Modified On  - Thu Jul 22 21:20:47 1999
;; Last Modified By  - Tim Bradshaw (tfb at lostwithiel.tfeb.org)
;; Update Count	     - 1
;; Status	     - Unknown
;; 
;; $Id$
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

(cl:defpackage "MULTIPLE-VALUE-BIND"
  (:nicknames "MVB")
  (:use "CL")
  (:export "BIND" "BIND*"))

(cl:in-package "MVB")

(defmacro bind (bindings &body bod)
  (if (find-if #'(lambda (b)
		   (and (consp b) (consp (car b))))
	       bindings)
      (expand-bind bindings '() bod)
      `(let ,bindings ,@bod)))

(defun expand-bind (bindings rebindings bod)
  (if (null bindings)
      `(let ,rebindings ,@bod)
      (let ((b (car bindings)))
	(etypecase b
	  (symbol
	   (expand-bind (cdr bindings) (cons b rebindings) bod))
	  (cons
	   (etypecase (car b)
	     (symbol
	      (expand-bind-let bindings '()
			       rebindings bod))
	     (cons
	      (expand-bind-mvb bindings rebindings bod))))))))

(defun expand-bind-let (bindings letbindings rebindings bod)
  (let ((b (car bindings)))
    (if (and (consp b) (symbolp (car b)))
	(let* ((vn (car b))
	       (vl (cadr b))
	       (vnn (make-symbol (symbol-name vn))))
	  (expand-bind-let (cdr bindings)
			   (cons `(,vnn ,vl)
				 letbindings)
			   (cons `(,vn ,vnn) rebindings)
			   bod))
	`(let ,(reverse letbindings)
	  ,(expand-bind bindings rebindings bod)))))

(defun expand-bind-mvb (bindings rebindings bod)
  (let* ((b (car bindings))
	 (bt (cdr bindings))
	 (vns (car b))
	 (vnns (mapcar #'(lambda (v)
			   (make-symbol (symbol-name v)))
		       vns))
	 (vls (cadr b)))
    `(multiple-value-bind ,vnns ,vls
      ,(expand-bind bt
		    (append (mapcar #'(lambda (v vn)
					`(,v ,vn))
				    vns vnns)
			    rebindings)
		    bod))))

(defmacro bind* (bindings &body bod)
  (if (find-if #'(lambda (b)
		   (and (consp b) (consp (car b))))
	       bindings)
      (expand-bind* bindings bod)
      `(let* ,bindings ,@bod)))


(defun expand-bind* (bindings bod)
  (if (null bindings)
      bod
      (let ((b (car bindings)))
	(etypecase b
	  (symbol
	   (expand-bind*-let* bindings '() bod))
	  (cons
	   (etypecase (car b)
	     (symbol
	      (expand-bind*-let* bindings '() bod))
	     (cons
	      (expand-bind*-mvb bindings bod))))))))

(defun expand-bind*-let* (bindings letbindings bod)
  (let ((b (car bindings)))
    (if (and b (or (symbolp b)
		   (and (consp b) (symbolp (car b)))))
	(expand-bind*-let* (cdr bindings)
			   (cons b letbindings) bod)
	;; I hate this
	(if bindings
	    `(let* ,(reverse letbindings)
	     ,(expand-bind* bindings bod))
	    `(let* ,(reverse letbindings)
	      ,@bod)))))

(defun expand-bind*-mvb (bindings bod)
  `(multiple-value-bind ,(caar bindings) ,(cadar bindings)
    ,(expand-bind* (cdr bindings) bod)))
From: David Bakhash
Subject: how about this `let' syntax?
Date: 
Message-ID: <cxjwvvo64jj.fsf_-_@acs5.bu.edu>
How about this syntax:

(let** ((x 1)
	((p (q r) s) '(a (b c) d)) ;; destructuring
	(:values f g h) (values "foo" "bar" "baz")
	t u     ;; will be nil, like (t nil) (u nil)
	(v) (w) ;; same here -- these will be nil too
	)
  <body here>)

If you look at this one, it seems compatible with the current let.  using
(:values ...) instead of (values ...) avoids the problem of `values' as a
symbol with a value and as a multiple-value indicator.  And it also allows for
destructuring.  I don't know about the rest.  Like, if someone wrote:

(let** ((:values w (x y) z) (values 3 '(4 5) 6))
  ...)

that's multiple-value and destructuring combined.  I think that should be
acceptable, though the details of it should be done by the experts :-)

Overall, wouldn't this `let' syntax be compatible with the current one?

dave
From: Vassil Nikolov
Subject: Re: how about this `let' syntax?
Date: 
Message-ID: <l03130300b3c10b43cc5c@195.138.129.100>
Tim Bradshaw wrote:                [1999-07-25 19:27 +0100]

  [...]
  > However the alternative, which is to write a new thing (like my
  > BIND/BIND*) which is a macro, is fraught because it is actually quite
  > hard to write such a macro and get it right.
  [...]

Would it be harder than LOOP?



Vassil Nikolov
Permanent forwarding e-mail: ········@poboxes.com
For more: http://www.poboxes.com/vnikolov
  Abaci lignei --- programmatici ferrei.
From: David Bakhash
Subject: Re: how about this `let' syntax?
Date: 
Message-ID: <cxjlnc45ar0.fsf@acs5.bu.edu>
Vassil Nikolov <········@poboxes.com> writes:

> Tim Bradshaw wrote:                [1999-07-25 19:27 +0100]
> 
>   [...]
>   > However the alternative, which is to write a new thing (like my
>   > BIND/BIND*) which is a macro, is fraught because it is actually quite
>   > hard to write such a macro and get it right.
>   [...]
> 
> Would it be harder than LOOP?

probably not.  But the point is that this new LET-like operator should not be
implemented as a macro, and need not take on a new name.  It should simply
extend LET in a syntactically backwards-compatible way.  In the meantime,
programmers can go crazy with their BIN/LETBIND and whatever temporary fixes
they like.

dave
From: Tim Bradshaw
Subject: Re: how about this `let' syntax?
Date: 
Message-ID: <ey3pv1gd1po.fsf@lostwithiel.tfeb.org>
* David Bakhash wrote:

> Overall, wouldn't this `let' syntax be compatible with the current one?

One of the good anti-new-LET arguments that has been raised is that
LET is a special operator in CL, not a macro.  Therefore any change to
what LET does involves changing any program-analysing code to
understand the new syntax.  Which means that any compiler has to know
about this change.  So it is a non-trivial change to the language, and
one which causes any old implementation to break in was which are not
fixable (you can't really patch it by macrology).

However the alternative, which is to write a new thing (like my
BIND/BIND*) which is a macro, is fraught because it is actually quite
hard to write such a macro and get it right.  It's hard because the
macro has to do analysis of declarations which may appear in the body
and sometimes `raise' them to be inside the expansion of the macro.
This is particularly true for LET* and SPECIAL declarations, but there
are other cases where you'd probably like to do it.

--tim
From: David Bakhash
Subject: Re: how about this `let' syntax?
Date: 
Message-ID: <cxjso6c5rhc.fsf@acs5.bu.edu>
I don't see your point.  So LET and LET* must be special operators.  This is a
fact, yes, but it does not mean that the syntax of a new let which behaves
equivalently as before when given equivalent arguments is a bad idea.

The fact that LET is a special operator only implies that a new conforming LET
will also be a special operator.  If the compiler sees the same thing given to
the new LET as to the old LET, then I believe it should do the same thing
(hence, backwards compatibility).  In cases where people use the new extended
LET syntax, then instead of spitting out an error, the compiler will DTRT.
What's the problem?

dave
From: Tim Bradshaw
Subject: Re: how about this `let' syntax?
Date: 
Message-ID: <ey3n1wkcnqk.fsf@lostwithiel.tfeb.org>
* David Bakhash wrote:
> The fact that LET is a special operator only implies that a new
> conforming LET will also be a special operator.  If the compiler
> sees the same thing given to the new LET as to the old LET, then I
> believe it should do the same thing (hence, backwards
> compatibility).  In cases where people use the new extended LET
> syntax, then instead of spitting out an error, the compiler will
> DTRT.  What's the problem?

The problem is that you can not change the syntax of LET without
changing every compiler, since it is a special operator. This is quite
different than just adding a macro or something, where you can simply
provide a definition for the macro which will allow an old conforming
implementation to be a new conforming implementation.  You can't do
that for LET, therefore a change to it is a much more severe change to
the language, and has potentially much higher cost to implementors.

--tim
From: Gareth McCaughan
Subject: Re: how about this `let' syntax?
Date: 
Message-ID: <866738fdtj.fsf@g.local>
David Bakhash wrote:

> I don't see your point.  So LET and LET* must be special operators.
> This is a fact, yes, but it does not mean that the syntax of a new
> let which behaves equivalently as before when given equivalent
> arguments is a bad idea.
> 
> The fact that LET is a special operator only implies that a new
> conforming LET will also be a special operator.  If the compiler
> sees the same thing given to the new LET as to the old LET, then I
> believe it should do the same thing (hence, backwards
> compatibility).  In cases where people use the new extended LET
> syntax, then instead of spitting out an error, the compiler will
> DTRT.  What's the problem?

That existing code-walkers will be broken if LET suddenly acquires
more syntax. This would not be a problem with a new *macro* called
LET** or LETBIND or BIND or whatever.

-- 
Gareth McCaughan  ················@pobox.com
sig under construction
From: David Bakhash
Subject: Re: how about this `let' syntax?
Date: 
Message-ID: <cxjn1wk5ax1.fsf@acs5.bu.edu>
Gareth McCaughan <················@pobox.com> writes:

> > The fact that LET is a special operator only implies that a new
> > conforming LET will also be a special operator.  If the compiler
> > sees the same thing given to the new LET as to the old LET, then I
> > believe it should do the same thing (hence, backwards
> > compatibility).  In cases where people use the new extended LET
> > syntax, then instead of spitting out an error, the compiler will
> > DTRT.  What's the problem?
> 
> That existing code-walkers will be broken if LET suddenly acquires
> more syntax. This would not be a problem with a new *macro* called
> LET** or LETBIND or BIND or whatever.

I'd much rather that the new LET be backwards compatible and be
re-implemented.  Sure, it's a pain.  But it's good to know that the
implementors and vendors will meet these challenges.  True that macros can do
a lot, but this is clearly a time when part of the language has the option to
grow, and surely those who are satisfied with the status quo will be against
the change.  I think it's worthwhile, and also that it will simplify the
language.

a simple call like:

(multiple-value-bind (a b c) (values-form)
  ...)

will now be:


(let ((:values a b c) (values-form))
  ...)

Just like #'(setf values) replaced multiple-value-setq (and then some), this
new let will replace multiple-value-bind.

If this weren't useful, then people wouldn't be trying so hard to write a
macro to do it.  It's really not meant to be a macro.  Also, I think that, if
a special operator, it can be optimized more effectively.  

When I wrote my example, I should have noted (though obvious) that the
declaration that's optional in a LET statement would be identical.  It's
really a good idea.  I'd like to see arguments that are more
language-engineering based than the issues of implementation effort.  LET,
mulitple-values, and destructuring are absolutely critical issues in Lisp.
They deserve the attention.

dave
From: Tim Bradshaw
Subject: Re: how about this `let' syntax?
Date: 
Message-ID: <ey3iu78c5x5.fsf@lostwithiel.tfeb.org>
> LET,
> mulitple-values, and destructuring are absolutely critical issues in Lisp.
> They deserve the attention.

I think that this is really the kind of hyperbole which you ought to
avoid.  For any reasonable definition of `critical' this is extremely
unlikely to be true.  If it was so important there would be a macro by
now: although it's hard, it's not impossible to do a semantically
correct one, and if you are happy doing some package trickery you can
even make it be called LET for your programs.

--tim
From: David Bakhash
Subject: Re: how about this `let' syntax?
Date: 
Message-ID: <cxjemhu68rc.fsf@acs5.bu.edu>
Tim Bradshaw <···@tfeb.org> writes:

> > LET,
> > mulitple-values, and destructuring are absolutely critical issues in Lisp.
> > They deserve the attention.
> 
> I think that this is really the kind of hyperbole which you ought to
> avoid.  For any reasonable definition of `critical' this is extremely
> unlikely to be true.  If it was so important there would be a macro by
> now: although it's hard, it's not impossible to do a semantically
> correct one, and if you are happy doing some package trickery you can
> even make it be called LET for your programs.

I disagree.  So many times my code is ridden with LETs nested within
MULTIPLE-VALUE-BINDs, and then LET again.  So many times I use LET* with
VALUES-LIST and then bind the individual arguments, just to avoid using
another structure:


(let* ((a 3)
       (val-list (values-list (foo)))
       (w (pop val-list))
       (x (pop val-list))
       (y (pop val-list))
       (z (pop val-list)))
  <body>)


(let* ((a 0)
       (val-list (multiple-value-list (foo)))
       (w (pop val-list))
       (x (pop val-list))
       (y (pop val-list))
       (z (pop val-list)))
  (list a w x y z))

instead of:

(let ((a 3)
      (:values w x y z) (foo)

I'm glad you have your opinion.  It deserves discussion.  I would tend to
believe that such a change would be welcomed and used enough that most people
would probably want to incorporate it without having to install the package.

dave  
From: Tim Bradshaw
Subject: Re: how about this `let' syntax?
Date: 
Message-ID: <ey3g12ad4z5.fsf@lostwithiel.tfeb.org>
* David Bakhash wrote:

> I disagree.  So many times my code is ridden with LETs nested within
> MULTIPLE-VALUE-BINDs, and then LET again.  So many times I use LET* with
> VALUES-LIST and then bind the individual arguments, just to avoid using
> another structure:

Have you written a macro to deal with it then?  If it is such pain for
you, I would expect you to have written one, like I did.  If you have
*not* written one, why?

--tim
From: David Bakhash
Subject: Re: how about this `let' syntax?
Date: 
Message-ID: <cxjbtcy5i9p.fsf@acs5.bu.edu>
The reason I didn't pour time into that macro was that there was already a
macro out there that did the same.  I tried using it, and then realized that
I wasn't satisfied with it.

Then I realized that I don't want to be using something second-rate, which (if
I tried to write this special LET, would be second rate).

In addition, I wasn't sure what I wanted.  I felt strongly that the new let
should:

1) be compatible with the old LET syntax, so I could us it interchangably,
   instead of adding yet another operator.
2) (maybe) have a SETF-like property so that you're really writing:

(LET ((PLACE VALUE)
      ...)
  <body>)

in which case it would be similar to LETF in the cl.el package for Emacs (see
cl-macs.el for the src).

3) it should handle both destructuring and multiple-values

I'm just happy that the issue has been raised, so those in the Lisp community
who feel repsonsible to listen to the needs and requests of the Lisp
community, and then discuss them, and come to conclusions.  I'm simply stating
my opionion.  If I had a macro which did a lot of this, it would not change my
opinion that LET should be extended in a backwards compatible way.

dave
From: Vassil Nikolov
Subject: Re: how about this `let' syntax?
Date: 
Message-ID: <l03130301b3c3d17e4c0b@195.138.129.101>
David Bakhash wrote:                [1999-07-27 09:33 -0400]

  [...]
  > 2) (maybe) have a SETF-like property so that you're really writing:
  > 
  > (LET ((PLACE VALUE)
  >       ...)
  >   <body>)
  > 
  > in which case it would be similar to LETF in the cl.el package for Emacs (see
  > cl-macs.el for the src).

LET does, or at least is free to do, deep binding (with variables).
LETF does shallow binding only (more precisely, I believe it is way
too painful to implement deep binding for places, if at all possible).
Therefore, IMO at least,
(1) giving `place' capabilities to LET is wrong;
(2) LETF is a misnomer---should be something like WITH-SAVED-PLACE
(assuming that `with' does not imply deep binding).

  > 3) it should handle both destructuring and multiple-values
  > 
  > I'm just happy that the issue has been raised, so those in the Lisp community
  > who feel repsonsible to listen to the needs and requests of the Lisp
  > community, and then discuss them, and come to conclusions
  [...]

The normal way for that to happen is illustrated by LOOP.  For some
time it was used experimentally and only then it became an official
part of the language.  (Compare the description of LOOP in CLtL and
CLtL2.)  I.e. cases like an extended binding form are not a matter of
listening to needs and coming to conclusions but a matter of someone
implementing it, then seeing if it is actually useful in practice.


Vassil Nikolov
Permanent forwarding e-mail: ········@poboxes.com
For more: http://www.poboxes.com/vnikolov
  Abaci lignei --- programmatici ferrei.
From: David Bakhash
Subject: Re: how about this `let' syntax?
Date: 
Message-ID: <cxjwvvj4m1o.fsf@acs5.bu.edu>
Vassil Nikolov <········@poboxes.com> writes:

> LET does, or at least is free to do, deep binding (with variables).
> LETF does shallow binding only (more precisely, I believe it is way
> too painful to implement deep binding for places, if at all possible).

yes.  I agree that it's painful, if done right.

> Therefore, IMO at least,
> (1) giving `place' capabilities to LET is wrong;

I also don't know how useful that would be.  it's nice in the generalized
sense of:

(letf (((values a b c) (returns-multiple-values)) ; multiple-values
       ((list x y z) (returns-a-list))            ; destructuring
       ...)
  <body>)
    
but I don't know how much people would put things like (aref a 5) in there.
hard to say.

>  > I'm just happy that the issue has been raised, so those in the Lisp 
>  > community
>  > who feel repsonsible to listen to the needs and requests of the Lisp
>  > community, and then discuss them, and come to conclusions
>  [...]

> The normal way for that to happen is illustrated by LOOP.  For some
> time it was used experimentally and only then it became an official
> part of the language.  (Compare the description of LOOP in CLtL and
> CLtL2.)  I.e. cases like an extended binding form are not a matter of
> listening to needs and coming to conclusions but a matter of someone
> implementing it, then seeing if it is actually useful in practice.

I wasn't in the game when LOOP was unofficial.  I always wondered if they were
considering the possibility of dealing with multiple-values.  Like, I end up
doing this a lot:

(loop
  for vals = (multiple-value-list (returns-multiple-values))
  for a = (first vals)
  and b = (second vals)
  and c = (third vals)
  ...)

that's not as pretty as:

(loop
  for (a b c) = (returns-multiple-values)
  ...)

or something along those lines.

Since LOOP now looks for atomic data after the FOR, that's always open to be
fixed, I guess.

dave
From: David Bakhash
Subject: Re: how about this `let' syntax?
Date: 
Message-ID: <cxjr9lq42ky.fsf@acs5.bu.edu>
Vassil Nikolov <········@poboxes.com> writes:

> LET does, or at least is free to do, deep binding (with variables).
> LETF does shallow binding only (more precisely, I believe it is way
> too painful to implement deep binding for places, if at all possible).

yes.  I agree that it's painful, if done right.

> Therefore, IMO at least,
> (1) giving `place' capabilities to LET is wrong;

I also don't know how useful that would be.  it's nice in the generalized
sense of:

(letf (((values a b c) (returns-multiple-values)) ; multiple-values
       ((list x y z) (returns-a-list))            ; destructuring
       ...)
  <body>)
    
but I don't know how much people would put things like (aref a 5) in there.
hard to say.

>  > I'm just happy that the issue has been raised, so those in the Lisp 
>  > community
>  > who feel repsonsible to listen to the needs and requests of the Lisp
>  > community, and then discuss them, and come to conclusions
>  [...]

> The normal way for that to happen is illustrated by LOOP.  For some
> time it was used experimentally and only then it became an official
> part of the language.  (Compare the description of LOOP in CLtL and
> CLtL2.)  I.e. cases like an extended binding form are not a matter of
> listening to needs and coming to conclusions but a matter of someone
> implementing it, then seeing if it is actually useful in practice.

I wasn't in the game when LOOP was unofficial.  I always wondered if they were
considering the possibility of dealing with multiple-values.  Like, I end up
doing this a lot:

(loop
  for (a b c) = (multiple-value-list (returns-multiple-values))
  ...)

that's not as pretty as:

(loop
  for (:values a b c) = (returns-multiple-values)
  ...)

but that's a minor point, I guess.

dave
From: Fernando Mato Mira
Subject: Re: how about this `let' syntax?
Date: 
Message-ID: <379B60F8.2520CDDA@iname.com>
Tim Bradshaw wrote:

> * David Bakhash wrote:
>
> > Overall, wouldn't this `let' syntax be compatible with the current one?
>
> One of the good anti-new-LET arguments that has been raised is that
> LET is a special operator in CL, not a macro.  Therefore any change to
> what LET does involves changing any program-analysing code to
> understand the new syntax.  Which means that any compiler has to know
> about this change.  So it is a non-trivial change to the language, and
> one which causes any old implementation to break in was which are not
> fixable (you can't really patch it by macrology).

Yes. That's an important reason, although somebody could say it's not such a
big deal, except in the case of unsupported implementations (read: hardware).

Of greater concern might be one one forward compatibility: if people start
using LET for MULTIPLE-VALUE-LET (now I think that name is right), who said
the Scheme people will follow?

Another important issue is that LET is on the critical path of any
interpreter.
You'd have to add at least a little testing for non-symbols where variables
usually go.
An implementation can now just assume they are all symbols and let the
underlying LAMBDA (or whatever) take the fall if you break the rules.
From: Fernando Mato Mira
Subject: Re: how about this `let' syntax?
Date: 
Message-ID: <379B5DE6.56486622@iname.com>
David Bakhash wrote:

> How about this syntax:
>
> (let** ((x 1)
>         ((p (q r) s) '(a (b c) d)) ;; destructuring
>         (:values f g h) (values "foo" "bar" "baz")
>         t u     ;; will be nil, like (t nil) (u nil)
>         (v) (w) ;; same here -- these will be nil too
>         )
>   <body here>)

And what does this mean?

((p (q r) s) (foo))
From: David Bakhash
Subject: Re: how about this `let' syntax?
Date: 
Message-ID: <cxju2qs5rrl.fsf@acs5.bu.edu>
Fernando Mato Mira <········@iname.com> writes:

> David Bakhash wrote:
> 
> > How about this syntax:
> >
> > (let** ((x 1)
> >         ((p (q r) s) '(a (b c) d)) ;; destructuring
> >         (:values f g h) (values "foo" "bar" "baz")
> >         t u     ;; will be nil, like (t nil) (u nil)
> >         (v) (w) ;; same here -- these will be nil too
> >         )
> >   <body here>)
> 
> And what does this mean?
> 
> ((p (q r) s) (foo))

since the RHS of each binding is evaluated, #'foo would be called with no
arguments and the output (presumably a list) would returned, just as in:

(destructuring-bind (p (q r) s) (foo)
  ...)

dave
From: Fernando Mato Mira
Subject: Re: how about this `let' syntax?
Date: 
Message-ID: <379C205B.1402909C@iname.com>
David Bakhash wrote:

> Fernando Mato Mira <········@iname.com> writes:
>
> > And what does this mean?
> >
> > ((p (q r) s) (foo))
>
> since the RHS of each binding is evaluated, #'foo would be called with no
> arguments and the output (presumably a list) would returned, just as in:
>
> (destructuring-bind (p (q r) s) (foo)
>   ...)
>
> dave

Sorry. I meant:

((p q r s) (foo))

What does _that_ mean? Even if you know that

(defun foo ()
    (values '(1 2 3 4) 5 6 7))

?
From: David Bakhash
Subject: Re: how about this `let' syntax?
Date: 
Message-ID: <cxjg12a69q8.fsf@acs5.bu.edu>
Fernando Mato Mira <········@iname.com> writes:

> David Bakhash wrote:
> 
> > Fernando Mato Mira <········@iname.com> writes:
> 
> ((p q r s) (foo))
> 
> What does _that_ mean? Even if you know that
> 
> (defun foo ()
>     (values '(1 2 3 4) 5 6 7))

As I said, the default behavior of the let should be destructuring, and the
:values form should be optional.  That way:

((p q r s) (values '(1 2 3 4) 5 6 7))

would bind:

p <= 1
q <= 2
r <= 3
s <= 4

If you wanted to bind multiple values:

((:values p q r s) (values '(1 2 3 4) 5 6 7))

then you get:

p <= '(1 2 3 4)
q <= 5
r <= 6
s <= 7

I think you were trying to make a point, but I don't know exactly what it
was.  is there some pathalogical case you see?  I don't see it.

dave
From: Fernando Mato Mira
Subject: Re: how about this `let' syntax?
Date: 
Message-ID: <379D7527.29ACFC87@iname.com>
David Bakhash wrote:

> ((:values p q r s) (values '(1 2 3 4) 5 6 7))

OK. That makes sense because keywords are supposed to bind to themselves only,
but maybe it would not too unreasonable to think that would be a notation for:

((:values p q r s) (values :values '(1 2 3 4) 5 6 7))

or in your case,

((:values p q r s) '(:values '(1 2 3 4) 5 6 7))

Meaning "I don't care about binding the first value. It should be :values, and
if it's not, you should raise an error", which kind of makes sense for
destructuring, as that :values could be part of the structure of the form.

Also, why should destructuring be more important? I think having to use
multiple values happens much more often.

Now a way out of all this, which makes a lot of sense after looking at the
semantics of LETBIND is:

(letbind (((a b c) (values (foo) (bar) (baz)))
          (((d e f)) (froboz))
          (((g h) i) (values (list (foo) (bar)) (baz))))
     ...)

-->

(multiple-value-call
  (lambda (a b c d g i)
    (destructuring-bind (d e f) d
      (destructuring-bind (g h) g
        ...)))
  (values (foo)(bar)(baz))
  (values (froboz))
  (values (list (foo) (bar)) (baz))))
From: David Bakhash
Subject: Re: how about this `let' syntax?
Date: 
Message-ID: <cxjd7xe5iux.fsf@acs5.bu.edu>
Fernando Mato Mira <········@iname.com> writes:

> David Bakhash wrote:
> 
> > ((:values p q r s) (values '(1 2 3 4) 5 6 7))
> 
> OK. That makes sense because keywords are supposed to bind to themselves only,
> but maybe it would not too unreasonable to think that would be a notation for:
> 
> ((:values p q r s) (values :values '(1 2 3 4) 5 6 7))

don't see your point.

> or in your case,
> 
> ((:values p q r s) '(:values '(1 2 3 4) 5 6 7))

it's a syntax.  You learn it, you use it.  period.

> Also, why should destructuring be more important? I think having to use
> multiple values happens much more often.

it's not.  It's just that it's more natural to do it that way.  That's how
lambda lists generally work, and LET is a close cousin.  Try looking at it the
other way, where multiple values are the default, and you use a :destructuring
keyword.  It's uglier.  Destructuring may not be used as much, but that's not
the point here.  I think this way is right, with :values.

> Now a way out of all this, which makes a lot of sense after looking at the
> semantics of LETBIND is:
> 
> (letbind (((a b c) (values (foo) (bar) (baz)))
>           (((d e f)) (froboz))
>           (((g h) i) (values (list (foo) (bar)) (baz))))
>      ...)

you think that's better than:

(let (((:values a b c) (values (foo) (bar) (baz)))
      ((d e f) (froboz))
      ((:values (g h) i) (values (list (foo) (bar)) (baz))))
   ...)

?  might agree with you on that one.  I think it's also compatible with the
old LET syntax, right?  You exchange the :values keyword for an extra list,
which I think is more than exceptable.  What do people like KMP think?

dave
From: Fernando Mato Mira
Subject: Re: LETBIND (why Tcl is more powerful than CL)
Date: 
Message-ID: <3797260A.47980337@iname.com>
Tim Bradshaw wrote:

> really good code for this. So I think there is some argument for just
> extending LET to allow the multiple-value syntax, which should be OK

NO, NO!

>
> because it can never clash with existing syntax that I can see.  Of
> course if you want multiple-values *and* destructuring you're in
> trouble, but I never want destructuring so I don't care (:-).

Or you have "perverted" ideas like:

(let (((x atype) (foo)))
   ...)

-->

(let ((x (foo)))
   (declare (type atype x))
   ...)
From: Marco Antoniotti
Subject: Re: LETBIND (why Tcl is more powerful than CL)
Date: 
Message-ID: <lwvhbczqqh.fsf@copernico.parades.rm.cnr.it>
Fernando Mato Mira <········@iname.com> writes:

> Tim Bradshaw wrote:
> 
> > really good code for this. So I think there is some argument for just
> > extending LET to allow the multiple-value syntax, which should be OK
> 
> NO, NO!
> 
> >
> > because it can never clash with existing syntax that I can see.  Of
> > course if you want multiple-values *and* destructuring you're in
> > trouble, but I never want destructuring so I don't care (:-).
> 
> Or you have "perverted" ideas like:
> 
> (let (((x atype) (foo)))
>    ...)
> 
> -->
> 
> (let ((x (foo)))
>    (declare (type atype x))
>    ...)


As a matter of fact

	(letbind ((a 22)
	  ((q w e) :values (values 1 2 3))
	  (qq 22 (fixnum qq))
	  (ee 33)
	  ((cc vv (hh &rest ll)) :structure '(11 22 (33 44 555 6666))
	   (fixnum cc vv hh)
	   (dynamic-extent ll))
	  )
	 (values a q w e qq ee cc vv hh ll))

Did I overshoot? :)

Cheers


-- 
Marco Antoniotti ===========================================
PARADES, Via San Pantaleo 66, I-00186 Rome, ITALY
tel. +39 - 06 68 10 03 17, fax. +39 - 06 68 80 79 26
http://www.parades.rm.cnr.it/~marcoxa
From: Fernando Mato Mira
Subject: Re: LETBIND (why Tcl is more powerful than CL)
Date: 
Message-ID: <3797391E.963C5527@iname.com>
Marco Antoniotti wrote:

> As a matter of fact
>
>         (letbind ((a 22)
>           ((q w e) :values (values 1 2 3))
>           (qq 22 (fixnum qq))
>           (ee 33)
>           ((cc vv (hh &rest ll)) :structure '(11 22 (33 44 555 6666))
>            (fixnum cc vv hh)
>            (dynamic-extent ll))
>           )
>          (values a q w e qq ee cc vv hh ll))
>
> Did I overshoot? :)

Now that we are having fun..

        (letbind ((a 22)
          ((q w e)@fixnum :values (values 1 2 3))
          (··@fixnum 22)
          (ee 33)
          ((cc vv (hh &rest ll)) :structure '(11 22 (33 44 555 6666))
           (fixnum cc vv hh)
           (dynamic-extent ll))
          )
         (values a q w e qq ee cc vv hh ll))

       (letbind ((a 22)
          ((q w e)@fixnum :values (values 1 2 3))
          (··@fixnum 22)
          (ee 33)
          ((cc vv (hh &rest ··@t))@fixnum :structure '(11 22 (33 44 555
6666))
           (dynamic-extent ll))
          )
         (values a q w e qq ee cc vv hh ll))
From: Fernando Mato Mira
Subject: Re: LETBIND (why Tcl is more powerful than CL)
Date: 
Message-ID: <37973BCD.DB770A71@iname.com>
Fernando Mato Mira wrote:

> Marco Antoniotti wrote:
>
> > As a matter of fact
> >
> >         (letbind ((a 22)
> >           ((q w e) :values (values 1 2 3))
> >           (qq 22 (fixnum qq))
> >           (ee 33)
> >           ((cc vv (hh &rest ll)) :structure '(11 22 (33 44 555 6666))
> >            (fixnum cc vv hh)
> >            (dynamic-extent ll))
> >           )
> >          (values a q w e qq ee cc vv hh ll))
> >
> > Did I overshoot? :)
>
> Now that we are having fun..
>
>         (letbind ((a 22)
>           ((q w e)@fixnum :values (values 1 2 3))
>           (··@fixnum 22)
>           (ee 33)
>           ((cc vv (hh &rest ll)) :structure '(11 22 (33 44 555 6666))
>            (fixnum cc vv hh)
>            (dynamic-extent ll))
>           )
>          (values a q w e qq ee cc vv hh ll))
>
>        (letbind ((a 22)
>           ((q w e)@fixnum :values (values 1 2 3))
>           (··@fixnum 22)
>           (ee 33)
>           ((cc vv (hh &rest ··@t))@fixnum :structure '(11 22 (33 44 555
> 6666))
>            (dynamic-extent ll))
>           )
>          (values a q w e qq ee cc vv hh ll))

Even better then:

         (letbind ((a 22)
           ((q w e) (values 1 2 3))
           (qq 22 fixnum)
           (ee :declare fixnum)
           ((ff gg) :declare fixnum)
           ((cc vv (hh &rest ll)) :structure '(11 22 (33 44 555 6666))
            (fixnum cc vv hh)
            (dynamic-extent ll))
           )
          (values a q w e qq ee cc vv hh ll))

        (letbind ((a 22)
          ((q w e)@fixnum (values 1 2 3))
          (··@fixnum 22)
          (··@fixnum)
          ((ff gg)@fixnum)
          ((cc vv (hh &rest ll)) :structure '(11 22 (33 44 555 6666))
           (fixnum cc vv hh)
           (dynamic-extent ll))
          )
         (values a q w e qq ee cc vv hh ll))

       (letbind ((a 22)
          ((q w e)@fixnum (values 1 2 3))
          (··@fixnum 22)
          (··@fixnum)
          ((ff gg)@fixnum)
          ((cc vv (hh &rest ··@t))@fixnum :structure '(11 22 (33 44 555
6666))
           (dynamic-extent ll))
          )
         (values a q w e qq ee cc vv hh ll))
From: Fernando Mato Mira
Subject: Re: LETBIND (why Tcl is more powerful than CL)
Date: 
Message-ID: <37973D6F.37ABF599@iname.com>
Fernando Mato Mira wrote:

>
>            (ee :declare fixnum)

BZZT

(ee 0 fixnum)
From: Fernando Mato Mira
Subject: Re: LETBIND (why Tcl is more powerful than CL)
Date: 
Message-ID: <379740AC.460B93CB@iname.com>
(a b (c d e) (f g h) (i j k &rest l))@{fixnum standard-object {(vector
float) &rest float} (vector float) {cons &rest (signed-byte 5)}}

Yeehaa!
From: Fernando Mato Mira
Subject: Re: LETBIND (why Tcl is more powerful than CL)
Date: 
Message-ID: <379721A7.3A7BC42F@iname.com>
What about:

(let ((A 1))
  (let ((a 2)
                    ((b c) :values (values a foo))
                    ((d e) (floor a 3)))
      ...))

-->

(LET ((A 1))
  (MULTIPLE-VALUE-CALL
      (LAMBDA (A B C D E)
          ....)
      2
     (VALUES A FOO)
     (FLOOR a 3)))
From: Fernando Mato Mira
Subject: Re: LETBIND (why Tcl is more powerful than CL)
Date: 
Message-ID: <3798460B.60C71720@iname.com>
More generally:

(let ((A 1))
  (letbind ((a (foo))
            (b (bar a))
            ((c d) (baz x))
            ((e f) (values 1 2 3))
            ((g h) (floor a 3))
            ((i) (cl:floor a 2)))
            ((j k l m) (values 1 2 (baz) (froboz))
            ((n o p)
             (values
               1
               (no-side-effects (side-effects (no-side-effects y)))
               3
               (no-side-effects (side-effects (no-side-effects y)))))
            ((q r) :structure (quux))
            ((s u) :structure l))
      ...))

-->

(let ((a 1))
  (multiple-value-call
      (lambda (a b c d e f g h i j k l m n o p #:s1 #:s2)
         (destructuring-bind (q r) #:s1
            (destructuring-bind (s u) #:s2
              ...)))
      (values (foo))
      (values (bar a))
      (multiple-value-bind (#:c #:d) (baz x)
                      (values #:c #:d))
      (values 1 2)
      (floor a 3) ; provided it's the actual CL:FLOOR, that is
      (values (cl:floor a 2))
      (values 1 2 (baz) (froboz))
      (funcall
         (lambda (#:o &rest #:dummy)
           (values 1 #:o 3))
         (no-side-effects (side-effects (no-side-effects y)))
         (side-effects (no-side-effects y)))
      (values (quux))
      l))


[That should be it for all the errors. Can I stop cancelling now? ;-)]
From: Erik Naggum
Subject: Re: LETBIND (why Tcl is more powerful than CL)
Date: 
Message-ID: <3141717521238085@naggum.no>
* Marco Antoniotti <·······@copernico.parades.rm.cnr.it>
| Which means that you'd have to code walk the RHSs and collect all
| possible free references to the outer environent, and then establish
| all the proper temporaries in the fashion I'd proposed.

  wouldn't it be enough to collect the variables actually bound by the
  form, collect all the values and then bind them in one fell swoop?  it
  appears to me that the problem is caused by the failure to obey the
  expected order of evaluation and binding.

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