From: Peter Seibel
Subject: Why no destructuring in ordinary lambda lists?
Date: 
Message-ID: <m33cd3d28t.fsf@javamonkey.com>
Is there a deep reason that ordinary lambda lists don't support
destructuring? Or just that's how history played out--it wasn't seen
as all that useful? Especially since one can always use
DESTRUCTURING-BIND to do runtime destructuring.

I realize that if one really wanted this "feature" one could shadow
DEFUN with something like:

  (defmacro defun (name (&rest lambda-list) &body body)
    (let ((args (gensym)))
      `(cl:defun ,name (&rest ,args)
         (destructuring-bind ,lambda-list ,args
           ,@body))))

But I was just curious, as always, about the history of these things.

-Peter

-- 
Peter Seibel                                      ·····@javamonkey.com

         Lisp is the red pill. -- John Fraser, comp.lang.lisp

From: Conrad Barski
Subject: Re: Why no destructuring in ordinary lambda lists?
Date: 
Message-ID: <a4af10cf.0311042207.31779acc@posting.google.com>
All I can say is, I had a "defun+" macro specifically for this
purpose, used it really heavily for a month or two, and somehow I just
found ways around using it. Recently I deleted the macro from my
library. I can't really explain why. It just seems to expose a lot of
the "guts" of the lisp engine unnecessarily, expecially because most
uses of such destructuring come up for trivial purposes, like
separating a single car from a cdr.
From: Barry Margolin
Subject: Re: Why no destructuring in ordinary lambda lists?
Date: 
Message-ID: <kJ8qb.367$lK3.187@news.level3.com>
In article <··············@javamonkey.com>,
Peter Seibel  <·····@javamonkey.com> wrote:
>Is there a deep reason that ordinary lambda lists don't support
>destructuring? Or just that's how history played out--it wasn't seen
>as all that useful? Especially since one can always use
>DESTRUCTURING-BIND to do runtime destructuring.

I think it's mostly a historical thing.  Macros tend to have lots of
structure in some of their parameters, so destructuring is an important
convenience.  If an ordinary function receives a parameter with lots of
internal structure, it's likely to be a true structure or class instance,
not a complex list that's amenable to destructuring.  The only cases where
I can imagine needing to destructure the arguments to an ordinary function
is if it's being used as an auxiliary by a macro, but even in this case I
would generally expect it to be destructured in the macro lambda list, and
then the extracted pieces passed to the helper function.

-- 
Barry Margolin, ··············@level3.com
Level(3), Woburn, MA
*** DON'T SEND TECHNICAL QUESTIONS DIRECTLY TO ME, post them to newsgroups.
Please DON'T copy followups to me -- I'll assume it wasn't posted to the group.
From: Kent M Pitman
Subject: Re: Why no destructuring in ordinary lambda lists?
Date: 
Message-ID: <wkr80mpump.fsf@nhplace.com>
Barry Margolin <··············@level3.com> writes:

> In article <··············@javamonkey.com>,
> Peter Seibel  <·····@javamonkey.com> wrote:
> >Is there a deep reason that ordinary lambda lists don't support
> >destructuring? Or just that's how history played out--it wasn't seen
> >as all that useful? Especially since one can always use
> >DESTRUCTURING-BIND to do runtime destructuring.
> 
> I think it's mostly a historical thing.  Macros tend to have lots of
> structure in some of their parameters, so destructuring is an important
> convenience.  If an ordinary function receives a parameter with lots of
> internal structure, it's likely to be a true structure or class instance,
> not a complex list that's amenable to destructuring.  The only cases where
> I can imagine needing to destructure the arguments to an ordinary function
> is if it's being used as an auxiliary by a macro, but even in this case I
> would generally expect it to be destructured in the macro lambda list, and
> then the extracted pieces passed to the helper function.

I agree with much of what you say here, Barry, but I don't know if I'd go
so far as to say that macros are the only big place that destructuring 
occurs. I often use it for "ad hoc structures" in situations like:

 (dolist (entry (loop for x in z
                      for i from 0
                      collect (cons i x)))
   (destructuring-bind (index . frob) entry
     ...))

so that I can assure that I'm destructuring things in the way I put them
together.

However, I think historically the reason it's not in arglists is that
arglist destructuring was a way of making the arglist mimic the look of
the call.  That is, you write:

 (dolist (i 10) ...)

so in defmacro you write:

 (defmacro dolist ((var val) &body forms) ...)

to mimic the shape of the actual dolist expression.  But in a function call,
it might not go that way.  Consider an operation like cadr, which you might
want to write as:

 (defun cadr ((car cadr &rest cddr))
   cadr)

The reason it's not done this way is that while you MIGHT write

 (cadr '(a b . ()))

you could just as well write

    (cadr (cons 3 x))
or  (cadr z)
or  (cadr (f g h))

and then the call would either not have the shape of the arglist
or the shape of the call being the shape of the arglist would be
coincidence.

In some sense, we have you pick up the argument first and then use
destructuring-bind to pick it apart to remind you that functional
evaluation is not about the shape of the argument form but the fact
that whatever the shape of that form, a single primary result will
be generated and used and that result needs itself to be named.
Once received, it is an internal decision of the function, not a
cooperative relationship between caller and callee, that involves
destructuring.

I hope that helps.
From: Peter Seibel
Subject: Re: Why no destructuring in ordinary lambda lists?
Date: 
Message-ID: <m3vfpyabpm.fsf@javamonkey.com>
Kent M Pitman <······@nhplace.com> writes:

> In some sense, we have you pick up the argument first and then use
> destructuring-bind to pick it apart to remind you that functional
> evaluation is not about the shape of the argument form but the fact
> that whatever the shape of that form, a single primary result will
> be generated and used and that result needs itself to be named.
> Once received, it is an internal decision of the function, not a
> cooperative relationship between caller and callee, that involves
> destructuring.
> 
> I hope that helps.

Yup. That's a useful way to look at it. Thanks.

-Peter

-- 
Peter Seibel                                      ·····@javamonkey.com

         Lisp is the red pill. -- John Fraser, comp.lang.lisp
From: Drew McDermott
Subject: Re: Why no destructuring in ordinary lambda lists?
Date: 
Message-ID: <bojro1$djv$1@news.wss.yale.edu>
Kent M Pitman wrote:

> ...and then the call would either not have the shape of the arglist
> or the shape of the call being the shape of the arglist would be
> coincidence.

This argument overlooks the fact that destructuring is the way almost 
all functional languages work (not to mention logic-programming languages).

The real reason (other than historical) why destructuring bind is not 
the norm in Lisp is that it would make lists too central, or maybe lists 
and vectors if you allowed destructuring by vector patterns. 
Functional languages usually take a more consistent algebraic approach 
to datatype definition than Lisp does.  In Lisp, you would need a way to 
"destructure structures"; I suppose you could write something like

    #S(strtype :field1 f &rest fl)

to extract field1 from a structure of type 'strtype' and store the value 
in 'f', while putting the values of the rest of the fields in the list 
'fl', but this raises all sorts of questions about the readability of 
expressions starting with "#S," whether to make the destructuring form 
of a structure look like its printed representation, what to do about 
CLOS-class instances, etc.

These problems don't arise for macros, where lists _are_ central.

I think Lisp's paradigm works quite well, even if it does look 
old-fashioned.  Any attempt to orient it around destructuring to a 
greater degree would probably make it worse.

-- 
                                    -- Drew McDermott
                                       Yale Computer Science Department
From: Kent M Pitman
Subject: Re: Why no destructuring in ordinary lambda lists?
Date: 
Message-ID: <sfwd6by55if.fsf@shell01.TheWorld.com>
Drew McDermott <··················@at.yale.dot.edu> writes:

> Kent M Pitman wrote:
> 
> > ...and then the call would either not have the shape of the arglist
> > or the shape of the call being the shape of the arglist would be
> > coincidence.
> 
> This argument overlooks the fact that destructuring is the way almost
> all functional languages work (not to mention logic-programming
> languages).
> 
> The real reason (other than historical) why destructuring bind is not
> the norm in Lisp is that it would make lists too central, or maybe
> lists and vectors if you allowed destructuring by vector
> patterns. Functional languages usually take a more consistent
> algebraic approach to datatype definition than Lisp does.  In Lisp,
> you would need a way to "destructure structures"; I suppose you could
> write something like
> 
>     #S(strtype :field1 f &rest fl)
> 
> to extract field1 from a structure of type 'strtype' and store the
> value in 'f', while putting the values of the rest of the fields in
> the list 'fl', but this raises all sorts of questions about the
> readability of expressions starting with "#S," whether to make the
> destructuring form of a structure look like its printed
> representation, what to do about CLOS-class instances, etc.
> 
> These problems don't arise for macros, where lists _are_ central.
> 
> I think Lisp's paradigm works quite well, even if it does look
> old-fashioned.  Any attempt to orient it around destructuring to a
> greater degree would probably make it worse.

Some good points, Drew.  Thanks for citing them.  I personally
remember this as having greater effect on LET's design than on
LAMBDA's, but the fact that I didn't see the effect you cite is not
proof that what you saw didn't always happen.  No single person sees
it from all points of view.

The place I remember representation being a strong affector was when
people proposed 

 (let (((x y) (list 3 4))) ...)

to work.  Stallman in particular suggested that

 (let (((list x y) (list 3 4))) ...)

was a better way of writing this destructuring (and destructuring 
in general) because he wanted to do:

 (defmacro make-point (x y) `(list ,x ,y))
 (let (((make-point x y) (make-point 3 4))) ...)

and then be able to change the representation, that is, to do

 (defmacro make-point (x y) `(vector ,x ,y))

and not have to rewrite the clients to do a different kind of destructuring.
A lot of people had sympathy for this, but it tended to work against the
easy-list-destructuring that macros used for the reasons you cite.
Having to use this more verbose style in the middle of a macro would have 
been fatal to the ease of macro programming, and so we backed off.

There were also some minor fussings as people edged closer to discussions
about 
 (let (((format "~A~A" x y) (format "~A~A" "foo" "bar")))
   ...)
and why you couldn't reliably get x and y bound to "foo" and "bar", even
though there were some patterns you could maybe get to work.

Anyway, I most certainly agree that the representation choice for lists
was an influence in the design of destructuring overall, but I just don't
know if it played specifically into the issue at the level of defun per se.

I do know also that it's the reason that keywords self-evaluate, in order
to support a similarity in calling style between macro &key args and
defun &key args, even though one kind is evaluated and the other kind is not.
By making them self-evaluate, you can pun that way.  This has led, however,
to a long list of individual surprises as one-by-one programmers  come up
against the differences in quoting for optionals in macros and optionals
in defun, the former requiring often one more level of ' than is intuitive,
but not always because often the default is self-evaluating and you don't
for a long time come up against things like:
 (defmacro frob (&optional (x 'y) ...) ...)
or
 (defmacro frob (&optional (x ''zing) ...) ...)
and are instead able to humor yourself into believing that extra quoting
isn't required by writing
 (defmacro frob (&optional (x 3) ...) ...)
where you mean
 (defmacro frob (&optional (x '3) ...) ...)

But I digress.