comp.emacs-lisp_lists_conceptual_tutorial_and_review

This is part of The Pile, a partial archive of some open source mailing lists and newsgroups.



From: Dan Debertin <airboss@nodewarrior.org>
Subject: elisp: adding a list as cdr
Newsgroups: comp.emacs
Date: 17 Feb 2003 13:51:36 -0600

I have an alist that contains one cons with nothing in the cdr:

(setq my-alist (list nil))
(setcar my-alist (cons "foo" nil))
==> (("foo"))

I want to set the cdr of the first elt of my-alist to a list, without
concatenating the two. I tried this:

(setf (cdr (assoc "foo" my-alist)) '(1 2 3))
==>(("foo" 1 2 3))

What I wanted to get was ("foo" . (1 2 3)). This sort of works:

(setcdr (assoc "foo" my-alist) '((1 2 3)))
==> (("foo" (1 2 3)))

But that makes it a list, not a single cons cell, and it will only
work in cases where the values being put into the cdr are literals,
not variables:

(setq list2 (list "goo" "baz" "crunch"))
(setcdr my-alist '(list2))
==> ("foo" list2)

How does one do this in elisp?

===

From: daniel@bigwalter.net (Daniel Jensen)
Subject: Re: elisp: adding a list as cdr
Newsgroups: comp.emacs
Date: Mon, 17 Feb 2003 22:08:30 +0100

Dan Debertin <airboss@nodewarrior.org> writes:

> I have an alist that contains one cons with nothing in the cdr:
>
> (setq my-alist (list nil))
> (setcar my-alist (cons "foo" nil))
> ==> (("foo"))
>
> I want to set the cdr of the first elt of my-alist to a list, without
> concatenating the two. I tried this:
>
> (setf (cdr (assoc "foo" my-alist)) '(1 2 3))
> ==>(("foo" 1 2 3))
>
> What I wanted to get was ("foo" . (1 2 3)).

And you got it; ("foo" . (1 2 3)) and ("foo" 1 2 3) are identical.

  (equal '("foo" . (1 2 3)) '("foo" 1 2 3)) => t

  (cdr (assoc "foo" my-alist)) => (1 2 3)

The dot notation will not be used if the cdr is a cons cell. In your
case, the cdr is a cons, so you get the usual list notation instead.

The dot is nothing magical, you can write any list with it if you
want:

  '(1 . (2 . (3 . nil))) => (1 2 3)

Just remember that a list is a chain of cons cells.

===

From: Dan Debertin <airboss@nodewarrior.org>
Subject: Re: elisp: adding a list as cdr
Newsgroups: comp.emacs
Date: 17 Feb 2003 16:38:11 -0600

daniel@bigwalter.net (Daniel Jensen) writes:

> > What I wanted to get was ("foo" . (1 2 3)).
> 
> And you got it; ("foo" . (1 2 3)) and ("foo" 1 2 3) are identical.
> 
>   (equal '("foo" . (1 2 3)) '("foo" 1 2 3)) => t
> 
>   (cdr (assoc "foo" my-alist)) => (1 2 3)

Hmm ... that throws me a bit. My understanding of the relationship
between cons cells and lists was that a solitary cons cell contained
data in both the car and the cdr, while a cons as part of a list had
data in the car and a pointer to the car of the next cons in the
cdr. Which explains:

(cdr (cons "foo" "bar"))
==> "bar"
(cdr (list "foo" "bar"))
==> ("bar")

So it didn't occur to me that it would work differently if "bar" was
another list instead of a string. Is the salient difference the fact
that lists aren't atoms?

What I was trying to do was make an alist of alists that referred to
lists of data, such that

(assoc "inner-car" (assoc "outer-car" my-alist))

would return

("inner-car" ("thing1" "thing2" "thing3"))

But I appear to have made this decision based on a misunderstanding of
how things work. 

===

From: Barry Margolin <barry.margolin@level3.com>
Subject: Re: elisp: adding a list as cdr
Newsgroups: comp.emacs
Date: Mon, 17 Feb 2003 23:27:11 GMT
Organization: Genuity Managed Services, Woburn, MA
Mail-Copies-To: never

In article <87adguy1m4.fsf@nodewarrior.org>,
Dan Debertin  <airboss@nodewarrior.org> wrote:
>daniel@bigwalter.net (Daniel Jensen) writes:
>
>> > What I wanted to get was ("foo" . (1 2 3)).
>> 
>> And you got it; ("foo" . (1 2 3)) and ("foo" 1 2 3) are identical.
>> 
>>   (equal '("foo" . (1 2 3)) '("foo" 1 2 3)) => t
>> 
>>   (cdr (assoc "foo" my-alist)) => (1 2 3)
>
>Hmm ... that throws me a bit. My understanding of the relationship
>between cons cells and lists was that a solitary cons cell contained
>data in both the car and the cdr, while a cons as part of a list had
>data in the car and a pointer to the car of the next cons in the
>cdr. Which explains:

No, it doesn't point to the car of the next cons, it points to the next
cons itself.  You can't point directly to a car or cdr.

>(cdr (cons "foo" "bar"))
>==> "bar"
>(cdr (list "foo" "bar"))
>==> ("bar")
>
>So it didn't occur to me that it would work differently if "bar" was
>another list instead of a string. Is the salient difference the fact
>that lists aren't atoms?

Lists are a high-level abstraction made from cons cells as the physical
building blocks.  If a cons cell's cdr is another cons cell or nil, it's
assumed to be part of a list's backbone, and printed as such.

In your case, the cdr is the list (1 2 3), which is represented as a cons
cell.  Lisp doesn't know whether you consider this the "next" cons in the
list or some unrelated cons -- it's just a cons.  For printing purposes,
it's treated as the next cons in the list.  The only time a "." is printed
is when the cdr points to something that isn't a cons or nil.

>What I was trying to do was make an alist of alists that referred to
>lists of data, such that
>
>(assoc "inner-car" (assoc "outer-car" my-alist))
>
>would return
>
>("inner-car" ("thing1" "thing2" "thing3"))
>
>But I appear to have made this decision based on a misunderstanding of
>how things work. 

It should be something like:

(assoc "inner-car" (cdr (assoc "outer-car" my-alist)))

because assoc returns the cons containing *both* the key and the data.

===

From: Dan Debertin <airboss@nodewarrior.org>
Subject: Re: elisp: adding a list as cdr
Newsgroups: comp.emacs
Date: 17 Feb 2003 19:37:01 -0600

Barry Margolin <barry.margolin@level3.com> writes:


> No, it doesn't point to the car of the next cons, it points to the next
> cons itself.  You can't point directly to a car or cdr.

Okay, I obviously imagined it to be more complicated than it is. No
surprise there.

Thanks for your patience; I understand more than I did a few hours
ago. A day well spent :).



===

From: daniel@bigwalter.net (Daniel Jensen)
Subject: Re: elisp: adding a list as cdr
Newsgroups: comp.emacs
Date: Tue, 18 Feb 2003 01:16:26 +0100

Dan Debertin <airboss@nodewarrior.org> writes:

> daniel@bigwalter.net (Daniel Jensen) writes:
>
>> > What I wanted to get was ("foo" . (1 2 3)).
>> 
>> And you got it; ("foo" . (1 2 3)) and ("foo" 1 2 3) are identical.
>> 
>>   (equal '("foo" . (1 2 3)) '("foo" 1 2 3)) => t
>> 
>>   (cdr (assoc "foo" my-alist)) => (1 2 3)
>
> Hmm ... that throws me a bit. My understanding of the relationship
> between cons cells and lists was that a solitary cons cell contained
> data in both the car and the cdr, while a cons as part of a list had
> data in the car and a pointer to the car of the next cons in the
> cdr.

Well, the cons cell doesn't actually store any data. It is really a
pair of pointers. It can be used as a 'pair' data type, most commonly
as a record in an assoc list. It can also be used as a linked list
element, with the car pointer pointing to an object of any kind, and
the cdr pointer pointing to another cons cell, the rest of the list.
(Also note that it does not point to the car of the rest of the list.)

It is usally not necessary to think of a list as a chain of cons
cells, but the knowledge of how lists are constructed may help you
understand recursive functions or lists used as specialized data
structures (such as assoc lists...)

> Which explains:
>
> (cdr (cons "foo" "bar"))
> ==> "bar"
> (cdr (list "foo" "bar"))
> ==> ("bar")

The dot notation helps visualize what happens here. (cons "foo" "bar")
creates the cons cell ("foo" . "bar"). (list "foo" "bar") creates the
cons cell ("bar" . nil) and then creates a cons cell with "foo" as car
and the previously created cons cell as cdr, resulting in
("foo" . ("bar" . nil)) or ("foo" "bar") for short. You can get the
same result by using cons twice; (cons "foo" (cons "bar" nil)).

What you need to understand is that there's no difference between a
cons cell and a list. The list is a cons cell with the cdr pointing to
another cons cell. You can think of the single cons cell (a . b) as a
broken list.

  (listp '(a . b)) => t
  (consp '(a b)) => t

The only exception is the empty list, nil, which is not a cons cell.

(I apologize if you already knew this.)

> So it didn't occur to me that it would work differently if "bar" was
> another list instead of a string. Is the salient difference the fact
> that lists aren't atoms?

The car and cdr functions don't care about what the cons cell
contains. They just follow the pointers and return whatever object
they find. I don't think understand what you mean here.

> What I was trying to do was make an alist of alists that referred to
> lists of data, such that
>
> (assoc "inner-car" (assoc "outer-car" my-alist))
>
> would return
>
> ("inner-car" ("thing1" "thing2" "thing3"))
>
> But I appear to have made this decision based on a misunderstanding of
> how things work. 

Yes. You want to use
(assoc "inner-car" (cdr (assoc "outer-car" my-alist))), and you want
it to return ("inner-car" "thing1" "thing2" "thing3").

===

From: Dan Debertin <airboss@nodewarrior.org>
Subject: Re: elisp: adding a list as cdr
Newsgroups: comp.emacs
Date: 17 Feb 2003 20:33:44 -0600

daniel@bigwalter.net (Daniel Jensen) writes:

[ very enlightening discussion of list construction ... ]

>
> What you need to understand is that there's no difference between a
> cons cell and a list. The list is a cons cell with the cdr pointing to
> another cons cell. You can think of the single cons cell (a . b) as a
> broken list.

As I said in response to Barry, my mental image of lists was more
complicated than they are (at this level of abstraction). I think I
got it from reading the Touretzky book, which uses block diagrams that
look like this:

+-----------+      +-----------+      +-----------+
|     |     |      |     |     |      |     |     |   |
| A   |  *--|----->|  B  |  *--|----->|  C  |  *--|---||
|     |     |      |     |     |      |     |     |   |
+-----------+      +-----------+      +-----------+

Which makes the cdr of the first cons and the car of the second appear
to be different things.

From Barry's and your explanations a more accurate picture would
be (excuse the horrible ASCII art):


+- - - - - -+
|   cons    |
+-----+-----+-----+-----+
|     |     |     |     |
|  A  |  B  |  C  | nil |
|     |     |     |     |
+-----+-----+-----+-----+
      |   cons    |     |
      +- - - - - -+     |
            |   cons    |
            +- - - - - -+

Actually, (cons 'foo (cons 'bar (cons 'baz nil))) is quite clear by itself.

>   (listp '(a . b)) => t
>   (consp '(a b)) => t
>
> The only exception is the empty list, nil, which is not a cons cell.
>
> (I apologize if you already knew this.)

I knew it only in the abstract sense; I appreciate the explanation.



===

From: Edward O'Connor <oconnor@soe.ucsd.edu>
Subject: Re: elisp: adding a list as cdr
Newsgroups: comp.emacs
Date: 17 Feb 2003 20:19:03 -0800
Organization: OEC, Jacobs School of Engineering, UCSD

Touretzky's diagram of (a b c):

> +-----------+      +-----------+      +-----------+
> |     |     |      |     |     |      |     |     |
> | A   |  *--|----->|  B  |  *--|----->|  C  |  *--|--- NIL
> |     |     |      |     |     |      |     |     |
> +-----------+      +-----------+      +-----------+

You're proposed diagram of (a b c):

> +- - - - - -+
> |   cons    |
> +-----+-----+-----+-----+
> |     |     |     |     |
> |  A  |  B  |  C  | nil |
> |     |     |     |     |
> +-----+-----+-----+-----+
>       |   cons    |     |
>       +- - - - - -+     |
>             |   cons    |
>             +- - - - - -+

This is not right Touretzky's diagram is more accurate. Perhaps it
would be best to draw it like this:


+-------+  
| cons  +  
+---+---+  
| A | *-+->+-------+  
+---+---+  | cons  +  
           +---+---+  
           | B | *-+->+-------+  
           +---+---+  | cons  +  
                      +---+---+  
                      | C | *-+->NIL
                      +---+---+  

That is, there is a cons whose car is A. Its cdr is a cons whose
car is B. _Its_ cdr is a cons whose car is C and whose cdr is NIL.

Does that help?

===

From: Oliver Scholz <alkibiades@gmx.de>
Subject: Re: elisp: adding a list as cdr
Newsgroups: comp.emacs
Date: Tue, 18 Feb 2003 10:44:17 +0100

Edward O'Connor <oconnor@soe.ucsd.edu> writes:

[...]
> This is not right Touretzky's diagram is more accurate. Perhaps it
> would be best to draw it like this:
>
>
> +-------+
> | cons  +
> +---+---+
> | A | *-+->+-------+
> +---+---+  | cons  +
>            +---+---+
>            | B | *-+->+-------+
>            +---+---+  | cons  +
>                       +---+---+
>                       | C | *-+->NIL
>                       +---+---+
>
[...]

FWIW, some time ago I saw one graphical representation of lists that I
found very helpful. I thought it was in "A Gentle Introduction to
Symbolic Computation" <URL: http://www-2.cs.cmu.edu/~dst/LispBook/>,
but I can't find it there at the moment. IIRC it goes like this:

(list 'alpha 'beta 'gamma)

      +---------------------------------+
      |         +----------------------+|
      |         |         +-----------+||
      |         |         |           |||
      | alpha   | beta    |gamma   nil|||
      |         |         |           |||
      |         |         +-----------+||
      |         +----------------------+|
      +---------------------------------+



===

From: kai.grossjohann@uni-duisburg.de (Kai Gro

the rest of The Pile (a partial mailing list archive)

doom@kzsu.stanford.edu