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

understanding destructuring-bind

195 views
Skip to first unread message

Jordan Katz

unread,
Feb 26, 2002, 11:09:34 PM2/26/02
to
Hi,

I've read both Graham's explanation and the Hyperspec's of
destructuring-bind, but it still makes no sense. As far as I
understand, the function takes a pattern of variables and then
applies that pattern to "an actual tree." That explanation makes
zero sense. Graham gives the following example:

(destructuring-bind (w (x y) . z) '(a (b c) d e) (list w x y z))
=> (A B C (D E))

So, if everthing in the actual tree is matched with the pattern in
the first argument, I'd assume that w in the actual list becomes a,
while (x y) becomes (b c), etc., but that's obviously not it
otherwise the resulting list would be (a (b c) e). How is
(A B C (D E)) achieved? I just can't make sense of this function. Can
someone explain?

Thanks a lot,
--
Jordan Katz <ka...@underlevel.net> | Mind the gap

Bruce Hoult

unread,
Feb 26, 2002, 10:44:06 PM2/26/02
to
In article <m3it8jv...@underlevel.underlevel.net>, Jordan Katz
<ka...@underlevel.net> wrote:

w <- 'a
x <- 'b
y <- 'c
z <- '(d e)


The example really shouldn't put w x y z into a list at the end because
it just confuses things.

HTH

-- Bruce

Larry Clapp

unread,
Feb 26, 2002, 10:53:29 PM2/26/02
to

You're close.

In the code above, destructuring-bind binds
the symbol w to the value a (i.e. (car '(a (b c) d e))),
the symbol x to the value b (i.e. (car (cadr '(a (b c) d e)))),
the symbol y to the value c (i.e. (cadr (cadr '(a (b c) d e)))),
and the symbol z to the value (d e) (i.e. (cddr '(a (b c) d e))).

Then, (list w x y z) generates a list equal to (list 'a 'b 'c '(d e)).

Similarly,

* (setq lst
'((1 2 3)
((4 5 6) (7 8 9))
(10 11 12) 13 14 15 16))

((1 2 3) ((4 5 6) (7 8 9)) (10 11 12) 13 14 15 16)
* (car lst)

(1 2 3)
* (car (cadr lst))

(4 5 6)
* (cadr (cadr lst))

(7 8 9)
* (cddr lst)

((10 11 12) 13 14 15 16)

* (destructuring-bind (w (x y) . z) lst


(list w x y z))

((1 2 3) (4 5 6) (7 8 9) ((10 11 12) 13 14 15 16))

Also, just by the by, you need the dot before the z:

* (destructuring-bind (w (x y) z) lst


(list w x y z))


Error while parsing arguments to DESTRUCTURING-BIND in COMMON-LISP::DO-ARG-COUNT-ERROR:
Invalid number of elements in:
((1 2 3) ((4 5 6) (7 8 9)) (10 11 12) 13 14 15 16)
to satisfy lambda-list:
(W (X Y) Z)
Expected exactly 3, but got 7.

Restarts:
0: [ABORT] Return to Top-Level.

Debug (type H for help)

("Top-Level Form")[:TOP-LEVEL]
Source: (DESTRUCTURING-BIND (W (X Y) Z) LST (LIST W X Y Z))
0]

The " . z)" is sort of equivalent to an &rest.

Does that help?

-- Larry

Coby Beck

unread,
Feb 26, 2002, 10:56:17 PM2/26/02
to

"Jordan Katz" <ka...@underlevel.net> wrote in message
news:m3it8jv...@underlevel.underlevel.net...

I think it is just a confusion with the call to list at the end. It is the
first two arguments to destructuring-bind that share the same structure. So
(w (x y) . z) matches (a (b c) . (d e)) After that you can do whatever you
want with your w x y z vars. In this case he justs returns them in a list.

--
Coby Beck
(remove #\Space "coby 101 @ bigpond . com")

Alexey Dejneka

unread,
Feb 26, 2002, 11:08:33 PM2/26/02
to
Hello,

Jordan Katz <ka...@underlevel.net> writes:
> (destructuring-bind (w (x y) . z) '(a (b c) d e) (list w x y z))
> => (A B C (D E))

(w (x y) . z) == (w . ((x . (y . nil)) . z ))
(a (b c) d e) == (a . ((b . (c . nil)) . (d . (e . nil)) ))

w <- a
x <- b
y <- c

z <- (d . (e . nil)) == (d e)

(list w x y z) => (a b c (d e))

> So, if everthing in the actual tree is matched with the pattern in
> the first argument, I'd assume that w in the actual list becomes a,
> while (x y) becomes (b c),

^^^^^^^ `is matched with', then X becomes B and Y becomes C,
so (LIST X Y) => (B C), and (LIST W X Y) => (A B C), *not* (A (B C)).

Regards,
Alexey Dejneka

---
Web-site owner! Protect your Intellectual Property! Do not allow all
those "visitors" see your genius creations!

Michael Hudson

unread,
Feb 27, 2002, 6:09:50 AM2/27/02
to
Jordan Katz <ka...@underlevel.net> writes:

> Hi,
>
> I've read both Graham's explanation and the Hyperspec's of
> destructuring-bind, but it still makes no sense. As far as I

> understand, the function ...
^^^^^^^^
Ain't a function.

Cheers,
M.

--
I have no disaster recovery plan for black holes, I'm afraid. Also
please be aware that if it one looks imminent I will be out rioting
and setting fire to McDonalds (always wanted to do that) and
probably not reading email anyway. -- Dan Barlow

Erik Naggum

unread,
Feb 27, 2002, 9:55:26 AM2/27/02
to
* Jordan Katz <ka...@underlevel.net>

| I've read both Graham's explanation and the Hyperspec's of
| destructuring-bind, but it still makes no sense.
:
| Can someone explain?

Let me start with the simplest example there is, a single variable:

(destructuring-bind (<variable>) <list>
<body>)

destructuring-bind hacks up <list> suck that the first (and probably
only) element in that list becomes the value of <variable> in <body>,
almost exactly like

(let ((<variable> (car <list>)))
<body>)

Now, suppose you make this a tad more complex, with a list of variables
and a list of values:

(destructuring-bind (<var1> <var2> <var3>) <list>
<body>)

(let ((<var1> (car <list>))
(<var2> (cadr <list>))
(<var3> (caddr <list>)))
<body>)

Finally, let us try with this "tree" notion, not just with a list of
variables:

(destructuring-bind (<var1> <var2> <var3> (<var4> <var5>)) <list>
<body>)

(let ((<var1> (car <list>))
(<var2> (cadr <list>))
(<var3> (caddr <list>))
(<var4> (car (cadddr <list)>))
(<var5> (cadr (cadddr <list)>)))
<body>)

So far, I have only mimicked the results of macroexpand on the
destructuring-bind form, but to macroexpand is intimately tied with the
function of destructuring-bind. There is another construct that uses
destructuring-bind in Common Lisp and that is macros, so if we do

(defmacro foo (<var1> <var2> <var3> (<var4> <var5>))
<body>)

we get exactly the same kind of destructuring when you evaluate the form
with a <list> equal to (1 2 3 (4 5)) as when you invoke (foo 1 2 3 (4 5)).

I hope this made it somewhat clearer what this binding form does and why
it is available to you as a Common Lisp programmer.

///
--
In a fight against something, the fight has value, victory has none.
In a fight for something, the fight is a loss, victory merely relief.

Håkon Alstadheim

unread,
Feb 27, 2002, 2:15:41 PM2/27/02
to
Jordan Katz <ka...@underlevel.net> writes:
[ ... snip ...]

> (destructuring-bind (w (x y) . z)
> '(a (b c) d e) (list w x y z))
> => (A B C (D E))

> How is (A B C (D E)) achieved? I just can't make sense of this
> function. Can someone explain?

Look at the shape of the last form. He is returning a "flattened"
tree. To get the result you evidently expected, you'd need to do

(destructuring-bind (w (x y) . z)

'(a (b c) d e) (list w (list x y ) z))
^^^^^^^^^^
Note
--
Håkon Alstadheim, hjemmepappa.

Thomas A. Russ

unread,
Feb 28, 2002, 3:34:10 PM2/28/02
to
Jordan Katz <ka...@underlevel.net> writes:

OK. What you start with is a pattern and then try to match that against
the incoming actual argument. What I didn't see explained in some of
the other responses is the role of the "." in the pattern. This
introduces a "dotted list" notation. You may not be familiar with it.
In essence what it does in the simple example (a . b) is make a match
the CAR of a form and b match the CDR (or FIRST and REST). This differs
from (a b) where a matches the CAR and b the CADR (or FIRST and SECOND).

(a b) a -> 1 ; b -> 2
| |
V V
(1 2)

(a . b) a -> 1 ; b -> (2 3 4 5)
| / \_
V V \
(1 2 3 4 5)

This is also done recursively, so that in the example from Graham:

(w (x y) . z) w -> a ; x -> b ; y -> c ; z -> (d e)
| | | /\
V V V V V


(a (b c) d e)


If the dot were not there, then the destructuring would fail, since the
pattern would not be able to match the actual input.

--
Thomas A. Russ, USC/Information Sciences Institute t...@isi.edu

Kenny Tilton

unread,
Mar 1, 2002, 5:34:28 AM3/1/02
to

"Thomas A. Russ" wrote:
>
> Jordan Katz <ka...@underlevel.net> writes:
>
> > Hi,
> >
> > I've read both Graham's explanation and the Hyperspec's of
> > destructuring-bind, but it still makes no sense. As far as I
> > understand, the function takes a pattern of variables and then
> > applies that pattern to "an actual tree." That explanation makes
> > zero sense. Graham gives the following example:
> >
> > (destructuring-bind (w (x y) . z) '(a (b c) d e) (list w x y z))
> > => (A B C (D E))
> >
> > So, if everthing in the actual tree is matched with the pattern in
> > the first argument, I'd assume that w in the actual list becomes a,
> > while (x y) becomes (b c), etc., but that's obviously not it
> > otherwise the resulting list would be (a (b c) e).

I am wondering how you get the match of of z to 'e. Were you thinking
the dot (.) matched 'd?

> How is
> > (A B C (D E)) achieved? I just can't make sense of this function.

Don't feel bad, I have been doing Lisp for quite a while now and I was
stumped by this example's use of a dot where I would have used &rest. To
my taste it was a mistake to confuse an introduction to one bit of
syntax (destructuring-bind) by throwing in a stumper like that.

Aside to Lisp veterans: y'all familiar with that usage? I can see how it
is mad faster than typing &rest...a harbinger of Arc to come?


--

kenny tilton
clinisys, inc
---------------------------------------------------------------
"Be the ball...be the ball...you're not being the ball, Danny."
- Ty, Caddy Shack

Geoff Summerhayes

unread,
Mar 1, 2002, 10:09:50 AM3/1/02
to

"Jordan Katz" <ka...@underlevel.net> wrote in message
news:m3it8jv...@underlevel.underlevel.net...

Everybody has given good explanations, I just thought I'd throw
in an ASCII diagram of the lists in case it wasn't clear.
Select a monospace font if you haven't already.

+---+---+ +---+---+
| | | | | |
| * | *---->| * | *----> Z
| | | | | | | |
+-|-+---+ +-|-+---+
| |
V V
+---+---+ +---+---+
W | | | | | |
| * | *---->| * | *----> nil
| | | | | | | |
+-|-+---+ +-|-+---+
| |
V V

X Y

+---+---+ +---+---+ +---+---+ +---+---+
| | | | | | | | | | | |
| * | *---->| * | *----->| * | *---->| * | *---->nil
| | | | | | | | | | | | | | | |
+-|-+---+ +-|-+---+ +-|-+---+ +-|-+---+
| | | |
V | V V
|
a | d e
V
+---+---+ +---+---+
| | | | | |
| * | *---->| * | *----> nil
| | | | | | | |
+-|-+---+ +-|-+---+
| |
V V

b c


Rahul Jain

unread,
Mar 1, 2002, 1:58:36 PM3/1/02
to
Kenny Tilton <kti...@nyc.rr.com> writes:

> Don't feel bad, I have been doing Lisp for quite a while now and I was
> stumped by this example's use of a dot where I would have used &rest.

> Aside to Lisp veterans: y'all familiar with that usage? I can see how it


> is mad faster than typing &rest...a harbinger of Arc to come?

I'm no veteran, but I doubt you can use (a &key b c . d) to mean the
same thing as (a &key b c &rest d). Also, it's probably an issue of
style, as you seem to have essentially asserted above. But considering
what I've seen of Arc so far, I would be surprised if it would add
lambda-list keywords in let-like binding forms when it doesn't (?)
have them in lambda-like ones.

--
-> -/- - Rahul Jain - -\- <-
-> -\- http://linux.rice.edu/~rahul -=- mailto:rj...@techie.com -/- <-
-> -/- "I never could get the hang of Thursdays." - HHGTTG by DNA -\- <-
|--|--------|--------------|----|-------------|------|---------|-----|-|
Version 11.423.999.221020101.23.50110101.042
(c)1996-2002, All rights reserved. Disclaimer available upon request.

Thomas F. Burdick

unread,
Mar 1, 2002, 3:18:15 PM3/1/02
to
Rahul Jain <rj...@sid-1129.sid.rice.edu> writes:

> Kenny Tilton <kti...@nyc.rr.com> writes:
>
> > Don't feel bad, I have been doing Lisp for quite a while now and I was
> > stumped by this example's use of a dot where I would have used &rest.
>
> > Aside to Lisp veterans: y'all familiar with that usage? I can see how it
> > is mad faster than typing &rest...a harbinger of Arc to come?

I'm not a veteran, but I use it all the time.

> I'm no veteran, but I doubt you can use (a &key b c . d) to mean the
> same thing as (a &key b c &rest d).

You're right; it's not a valid construct. Mixing &key and . isn't
allowed, for I hink pretty obvious reasons. I would expect D in
(a &key b c . d) to always be NIL (because after all the keys, there's
nothing left in the list). However, what would you do with:

(destructuring-bind
(a &key b c &allow-other-keys . d)
'(1 :foo "foo" :bar "bar" :b 2 :c 3)
d)

Should it be (:foo "foo" :bar "bar")? Or what? It doesn't really
make sense to have a dot after a &key.

--
/|_ .-----------------------.
,' .\ / | No to Imperialist war |
,--' _,' | Wage class war! |
/ / `-----------------------'
( -. |
| ) |
(`-. '--.)
`. )----'

0 new messages