From: David Pollen
Subject: Nil Question
Date: 
Message-ID: <pollenCrz5wB.Aox@netcom.com>
While is Nil an Atom, and why do first rest and second applied to it
return Nil instead of some sort of error?

What is the reasoning by the creators of the language for this?

From: Henry G. Baker
Subject: Re: Nil Question
Date: 
Message-ID: <hbakerCrz771.15t@netcom.com>
In article <················@netcom.com> ······@netcom.com (David Pollen) writes:
>While is Nil an Atom, and why do first rest and second applied to it
>return Nil instead of some sort of error?
>
>What is the reasoning by the creators of the language for this?

I seem to recall that MIT Lisp (Maclisp) _did_ give you an error on
this.  However, I think that BBN/Xerox Interlisp used this hack to get
at the equivalent of '&optional' and '&rest' arguments, so they
depended on this hack quite a bit.  I think that one of the
compromises for 'Common Lisp' was to keep the Interlisp behavior, even
though Common Lisp now provides &optional and &rest arguments to do
the same thing.

Perhaps someone from the Interlisp camp can respond with their
recollections.  (My Interlisp manual was lost years ago, otherwise I
would have looked it up.)

-----

In my experience, I would just as soon that '() were _not_ a symbol,
but simply an atom (non-CONS).  Furthermore, I would just as soon that
(eq '() #f) => #f, since the concept of an empty list and the concept
of 'false' are totally unrelated.  A compiler can help you more if it
has a bit more redundancy, and redundancy of this form would help
human readers, as well.
From: Barry Margolin
Subject: Re: Nil Question
Date: 
Message-ID: <2un1l9INNeld@early-bird.think.com>
In article <················@netcom.com> ······@netcom.com (Henry G. Baker) writes:
>In article <················@netcom.com> ······@netcom.com (David Pollen) writes:
>>While is Nil an Atom, and why do first rest and second applied to it
>>return Nil instead of some sort of error?
>I seem to recall that MIT Lisp (Maclisp) _did_ give you an error on
>this.  

Actually, it had a parameter variable that allowed you to enable and
disable this error.

I recall that there was lots of debate on the COMMON-LISP mailing list
about this when the language was being designed, although I don't remember
specific details.

One feature of this treatment of NIL is that it permits using the derived
functions like CAAR and CDDR more easily.  If you want to test whether a
list is at least 4 element long, you can write (NTHCDR 3 expression) rather
than (LET ((T expression)) (AND T (CDR T) (CDDR T) (CDDDR T)).
-- 
Barry Margolin
System Manager, Thinking Machines Corp.

······@think.com          {uunet,harvard}!think!barmar
From: Erann Gat
Subject: Re: Nil Question
Date: 
Message-ID: <gat-270694114338@silicon.jpl.nasa.gov>
In article <············@early-bird.think.com>, ······@think.com (Barry
Margolin) wrote:

> If you want to test whether a
> list is at least 4 element long, you can write (NTHCDR 3 expression) rather
> than (LET ((T expression)) (AND T (CDR T) (CDDR T) (CDDDR T)).

If you want to test whether a list is at least 4 elements long you should
write (>= (LENGTH expression) 4).  (Not to mention the fact that T is a
constant and can't be used as a lexical variable.)  C'mon Barry,
you can come up with a better example than that!  :-)

E.

-- 

Erann Gat
···@robotics.jpl.nasa.gov
From: Erann Gat
Subject: Re: Nil Question
Date: 
Message-ID: <gat-270694132928@silicon.jpl.nasa.gov>
In article <················@silicon.jpl.nasa.gov>, I wrote:

> In article <············@early-bird.think.com>, ······@think.com (Barry
> Margolin) wrote:
> 
> > If you want to test whether a
> > list is at least 4 element long, you can write (NTHCDR 3 expression) rather
> > than (LET ((T expression)) (AND T (CDR T) (CDDR T) (CDDDR T)).
> 
> If you want to test whether a list is at least 4 elements long you should
> write (>= (LENGTH expression) 4).

Thanks to Peter Norvig for pointing out that Barry's code is O(1) and mine
is O(n).  I'm not sure where my brain was when I wrote this.  Sorry, Barry.

E.

-- 

Erann Gat
···@robotics.jpl.nasa.gov
From: Richard Lynch
Subject: Re: Nil Question
Date: 
Message-ID: <lynch-270694223305@lynch.ils.nwu.edu>
In article <················@silicon.jpl.nasa.gov>,
···@robotics.jpl.nasa.gov (Erann Gat) wrote:

> In article <················@silicon.jpl.nasa.gov>, I wrote:
> 
> > In article <············@early-bird.think.com>, ······@think.com (Barry
> > Margolin) wrote:
> > 
> > > If you want to test whether a
> > > list is at least 4 element long, you can write (NTHCDR 3 expression) rather
> > > than (LET ((T expression)) (AND T (CDR T) (CDDR T) (CDDDR T)).
> > 
> > If you want to test whether a list is at least 4 elements long you should
> > write (>= (LENGTH expression) 4).
> 
> Thanks to Peter Norvig for pointing out that Barry's code is O(1) and mine
> is O(n).  I'm not sure where my brain was when I wrote this.  Sorry, Barry.

You *were* correct about the use of T, though.  :-)

I once convinced myself that MCL cached the length of a list so that
(length list) would be O(1).  That doesn't mean it's true; it just means I
was convinced it was true.  :-)   It does seem a reasonable thing to do, if
it could be done cheaply enough...

Finally, as far as hacks go, I recall finding out in college that in
Standard LISP (car 'symbol) would return a hex address which I presumed to
be the actual address of the symbol structure.  (cdr 'symbol)
returned...hm, I forget what it returned...the property list maybe?

-- 
-- 
--
-- "TANSTAAFL"  Rich ·····@ils.nwu.edu
From: John Fitch
Subject: Re: Nil Question
Date: 
Message-ID: <Cs3sz3.E9s@midge.bath.ac.uk>
>>>>> "Richard" == Richard Lynch <·····@ils.nwu.edu> writes:
In article <··················@lynch.ils.nwu.edu> ·····@ils.nwu.edu (Richard Lynch) writes:

    Richard> Finally, as far as hacks go, I recall finding out in
    Richard> college that in Standard LISP (car 'symbol) would return
    Richard> a hex address which I presumed to be the actual address
    Richard> of the symbol structure.  (cdr 'symbol) returned...hm, I
    Richard> forget what it returned...the property list maybe?

In Standard LISP car or cdr of an identifier is an error.  What is the
case is that one implementation did not check, and (cdr 'foo) was the
property list of foo. 

As an aside to this, on at least one of my machines length was in
microcode as while O(n) the constant was very small, so it looked like
O(1).

==John ff
From: Barry Margolin
Subject: Re: Nil Question
Date: 
Message-ID: <2usadpINNfje@early-bird.think.com>
In article <··················@lynch.ils.nwu.edu> ·····@ils.nwu.edu (Richard Lynch) writes:
>I once convinced myself that MCL cached the length of a list so that
>(length list) would be O(1).  That doesn't mean it's true; it just means I
>was convinced it was true.  :-)   It does seem a reasonable thing to do, if
>it could be done cheaply enough...

It doesn't seem like it would work very well.  If the cache is keyed off
the head of the list, and you RPLACD some later element of the list, how
would it know to update the cache for the earlier elements?  Either you
flush the cache on every RPLACD, or there would have to be back-pointers
from every cons that was part of a list whose length was cached to all the
cache entries for it (it could be the tail of multiple lists).
-- 
Barry Margolin
System Manager, Thinking Machines Corp.

······@think.com          {uunet,harvard}!think!barmar
From: Marty Hall
Subject: Re: Nil Question
Date: 
Message-ID: <Cs2r0F.1x7@aplcenmp.apl.jhu.edu>
···@robotics.jpl.nasa.gov (Erann Gat) writes:
>······@think.com (Barry Margolin) wrote:
>
>> If you want to test whether a
>> list is at least 4 element long, you can write (NTHCDR 3 expression) rather
>> than (LET ((T expression)) (AND T (CDR T) (CDDR T) (CDDDR T)).
>
>If you want to test whether a list is at least 4 elements long you should
>write (>= (LENGTH expression) 4).  

(>= (length expression) 4) does seem clearer. However, since LENGTH
is O(N), this can be very expensive if your lists are long.
(nthcdr 3 expression) is O(1).
						- Marty
(proclaim '(inline skates))
From: Robert Virding
Subject: Re: Nil Question
Date: 
Message-ID: <2us0ud$6vg@euas20.eua.ericsson.se>
In article <··········@aplcenmp.apl.jhu.edu>, ····@aplcenmp.apl.jhu.edu (Marty Hall) writes:
>···@robotics.jpl.nasa.gov (Erann Gat) writes:
>>······@think.com (Barry Margolin) wrote:
>>
>>> If you want to test whether a
>>> list is at least 4 element long, you can write (NTHCDR 3 expression) rather
>>> than (LET ((T expression)) (AND T (CDR T) (CDDR T) (CDDDR T)).
>>
>>If you want to test whether a list is at least 4 elements long you should
>>write (>= (LENGTH expression) 4).  
>
>(>= (length expression) 4) does seem clearer. However, since LENGTH
>is O(N), this can be very expensive if your lists are long.
>(nthcdr 3 expression) is O(1).

Totally wrong!! NTHCDR has to traverse the list just like any other
list processing function, for example LENGTH.

	Robert
From: Robert Sanders
Subject: Re: Nil Question
Date: 
Message-ID: <RSANDERS.94Jun29133841@hrothgar.mindspring.com>
In article <··········@euas20.eua.ericsson.se> ··@erix.ericsson.se (Robert Virding) writes:

   In article <··········@aplcenmp.apl.jhu.edu>, ····@aplcenmp.apl.jhu.edu (Marty Hall) writes:
   >···@robotics.jpl.nasa.gov (Erann Gat) writes:
   >>If you want to test whether a list is at least 4 elements long you should
   >>write (>= (LENGTH expression) 4).  
   >
   >(>= (length expression) 4) does seem clearer. However, since LENGTH
   >is O(N), this can be very expensive if your lists are long.
   >(nthcdr 3 expression) is O(1).

   Totally wrong!! NTHCDR has to traverse the list just like any other
   list processing function, for example LENGTH.

Er, you're technically right, but you miss the point.  Let's say you
wanted a function that returned some true value or nil depending on
whether the list was 4 or more elements long.  The implementation
using (NTHCDR 3 expression) is O(1); it doesn't vary with the length
of the list expression because (NTHCDR 3 expression) only needs to
traverse until the nth CDR.  The implementation using (>= (LENGTH
expression) 4) is O(n) because LENGTH must always traverse the
*entire* list.

And people wonder why it's so easy to write slow LISP.

  -- Robert
From: Brad Miller
Subject: Re: Nil Question
Date: 
Message-ID: <MILLER.94Jun29141440@wolverine.cs.rochester.edu>
>>>>> "Robert" == Robert Virding <··@erix.ericsson.se> writes:
        >···@robotics.jpl.nasa.gov (Erann Gat) writes:

        >(>= (length expression) 4) does seem clearer. However, since LENGTH
        >is O(N), this can be very expensive if your lists are long.
        >(nthcdr 3 expression) is O(1).

    Robert> Totally wrong!! NTHCDR has to traverse the list just like any other list processing function, for example
    Robert> LENGTH.

    Robert> 	Robert

You don't understand. Nthcdr has to traverse (in this example) 
4 elements of the list, length has to traverse the enitre
list, even if it is 200000000 elements, to return the length.

Therefore (nthcdr n l) is O(n), with (length l) is O(|l|).

For a constant c, (nthcdr c l), is O(c) or O(1).

Regards,
--
Brad Miller                    ······@cs.rochester.edu
Computer Science Dept.         http://www.cs.rochester.edu/u/miller/
University of Rochester        716-275-1118 (v) 461-2018 (f)
Rochester, NY 14627-0226
From: Mark J. Dulcey
Subject: Re: Nil Question
Date: 
Message-ID: <772936102.81snx@pryder.pn.com>
In article <··········@euas20.eua.ericsson.se> ··@erix.ericsson.se writes:
>
>In article <··········@aplcenmp.apl.jhu.edu>, ····@aplcenmp.apl.jhu.edu (Marty> Hall) writes:
>>···@robotics.jpl.nasa.gov (Erann Gat) writes:
>>>······@think.com (Barry Margolin) wrote:
>>>
>>>If you want to test whether a list is at least 4 elements long you should
>>>write (>= (LENGTH expression) 4).  
>>
>>(>= (length expression) 4) does seem clearer. However, since LENGTH
>>is O(N), this can be very expensive if your lists are long.
>>(nthcdr 3 expression) is O(1).
>
>Totally wrong!! NTHCDR has to traverse the list just like any other
>list processing function, for example LENGTH.

(NTHCDR 3 foo) only has to traverse the first 3 elements of the list.
(LENGTH foo) might have to count thousands!
From: Barry Margolin
Subject: Re: Nil Question
Date: 
Message-ID: <2usalcINNfnk@early-bird.think.com>
In article <··········@aplcenmp.apl.jhu.edu> ····@aplcenmp.apl.jhu.edu (Marty Hall) writes:
>···@robotics.jpl.nasa.gov (Erann Gat) writes:
>>If you want to test whether a list is at least 4 elements long you should
>>write (>= (LENGTH expression) 4).  
>
>(>= (length expression) 4) does seem clearer. However, since LENGTH
>is O(N), this can be very expensive if your lists are long.
>(nthcdr 3 expression) is O(1).

In fact, there was a proposal in X3J13 to add an optional argument to
LENGTH (or maybe it was LIST-LENGTH), to tell it how far to go before
giving up.

The proposal wasn't accepted.  One argument against it was that compilers
could recognize (> (LENGTH exp1) exp2) and generate the appropriate O(1)
code.  I don't know whether any compilers do this, though.

-- 
Barry Margolin
System Manager, Thinking Machines Corp.

······@think.com          {uunet,harvard}!think!barmar
From: Marty Hall
Subject: Re: Nil Question
Date: 
Message-ID: <Cs66po.705@aplcenmp.apl.jhu.edu>
······@think.com (Barry Margolin) writes:
[...]
<In fact, there was a proposal in X3J13 to add an optional argument to
<LENGTH (or maybe it was LIST-LENGTH), to tell it how far to go before
<giving up.
<
<The proposal wasn't accepted.  One argument against it was that compilers
<could recognize (> (LENGTH exp1) exp2) and generate the appropriate O(1)
<code.  I don't know whether any compilers do this, though.

Ah, the infamous SSC (sufficiently smart compiler) syndrome. :-(
But I'm not sure I would have voted for an optional argument to LENGTH, either.

					- Marty
From: Martin Rodgers
Subject: Re: Nil Question
Date: 
Message-ID: <773440224snz@wildcard.demon.co.uk>
In article <···············@vegas.cs.brown.edu>
           ··@cs.brown.edu "rodrigo vanegas" writes:

>   > (defun length (l) 42)
>   ;;; Warning: Redefining Function LENGTH whose source-file was not recorded
>  
>   Nasty recursive error in debugger.
>  
>   Serious problems.  Will attempt return to top level of lisp...
>  
>   Serious problems.  Will attempt return to top level of lisp...
>  
>   Serious problems.  Will attempt return to top level of lisp...
>  
> Ad infinitum... 
> 
> Hey, Lucid!  Are you listening?

I tried something similar in CLISP, and got this:

> (length '(1 2 3))
3
> (defun length (l)    42)
LENGTH
> (length '(1 2 3))
42

What you don't see above, coz CLISP's dribble doesn't record it,
is that CLISP asks you if you really want to redefine the function,
and allows you to keep the original if you want to.

-- 
Martin Rodgers, WKBBG, London UK   AKA "Cyber Surfer"

If "One likes to believe in the freedom of email", email
················@cpsr.org and tell them you oppose Clipper.
This is a shareware .signature  -- please pass it on!
From: Bruno Haible
Subject: Re: Redefining CL functions (was: Nil Question)
Date: 
Message-ID: <2ve92h$969@nz12.rz.uni-karlsruhe.de>
Martin Rodgers <············@wildcard.demon.co.uk> wrote:
>
> I tried something similar in CLISP, and got this:
>
> > (length '(1 2 3))
> 3
> > (defun length (l)    42)
> LENGTH
> > (length '(1 2 3))
> 42

CLISP isn't vulnerable here because it compiles LENGTH inline, so most
parts of the system won't notice the new definition of LENGTH.

Another good attack on your Lisp is
   (DO-ALL-SYMBOLS (S) (UNLESS (CONSTANTP S) (SET S NIL)))
How do different Common Lisp implementations react on this?

               Bruno Haible
From: Martin Rodgers
Subject: Re: Redefining CL functions (was: Nil Question)
Date: 
Message-ID: <773599731snz@wildcard.demon.co.uk>
In article <··········@nz12.rz.uni-karlsruhe.de>
           ······@ma2s2.mathematik.uni-karlsruhe.de "Bruno Haible" writes:

> CLISP isn't vulnerable here because it compiles LENGTH inline, so most
> parts of the system won't notice the new definition of LENGTH.

My point was simply that CLISP give me a warning and a choice.
Perhaps I should have made that clearer. :-)

CLISP is my favourite Lisp right now, as it can do all the things
I currently want, except run as a native MS Windows app. There are
Windows extenders that can fix this, but they cost too much - I could
by Allegro CL/PC for less money. So, I don't mind a few limitations,
and CLISP has none that are a pain.

It just means I can't use the Windows clipboard as easily, but dribble
is a simple work-around, or I can use the klunky clipboard menu for DOS
apps. Even if I succeeded in writing my own 32bit Windows extender, I
doubt I could make it as good as I'd need. That's a nature of users,
we put more and more stress on software, expecting more and more from
it until it breaks.

I'm glad to say that CLISP doesn't break easily, and it all depends
on what you you expect. No Lisp I've used has been as easy to use as
VB, but that could change. As I implied above, I don't yet use Allegro
CL/PC, or CLISP with the X-Windows extensions. Which one I eventually
uses will depend probably on my future as a programmer. If I'm not
being paid to use MS software, I'll prefer Linux and CLISP.

-- 
Martin Rodgers, WKBBG, London UK   AKA "Cyber Surfer"

If "One likes to believe in the freedom of email", email
················@cpsr.org and tell them you oppose Clipper.
This is a shareware .signature  -- please pass it on!
From: Simon Brooke
Subject: Re: Nil Question
Date: 
Message-ID: <CsL6tp.8q@exnet.com>
In article <··········@triple-i.com> ····@triple-i.com (Kirk Rader) writes:
>In article <·········@exnet.com> ····@exnet.com (Simon Brooke) writes:
>>Look, guys, maybe I'm slow or maybe I'm missing the point. Put suppose
>>nil is a list (which it is) then car of nil should be legal -- and
>               ^^^^^^^^^^^^
>
>This is the crux of the debate.  It seems entirely logical that (CAR
>'()) and (CAR NIL) should be legal - and return NIL - if (EQ NIL '())
>is true.  But IMHO (EQ NIL '()) should be _false_ in any "sane LISPs".
>
....
>
>How can muddling the logically distinct types "symbol", "list", and
>"boolean" be less daft than introducing a needless and
>counter-productive proliferation of name spaces? :-)
>
OK, there *is* a point here, but not one I have any difficulty with.
Infinity, zero and the empty set all have paradoxical properties: that's
one of the things that happens at limits. The empty list is a limit.
Hence it behaves in odd ways. If you want to use a different value for
false, that's easy:

(setq false '())



-- 
    .::;====r==\              ····@uk.co.exnet (Simon Brooke)
   /  /____||___\____         MS Windows IS an operating environment.      
  //==\   ~||~  |  /__\(      C++ IS an object oriented programming language. 
 //____\___||___|_//  \|:     Citroen 2cv6 IS a four door family saloon.
From: Kirk Rader
Subject: Re: Nil Question
Date: 
Message-ID: <CsMMr3.JIn@triple-i.com>
In article <·········@exnet.com> ····@exnet.com (Simon Brooke) writes:
>In article <··········@triple-i.com> ····@triple-i.com (Kirk Rader) writes:
>>In article <·········@exnet.com> ····@exnet.com (Simon Brooke) writes:
>>>Look, guys, maybe I'm slow or maybe I'm missing the point. Put suppose
>>>nil is a list (which it is) then car of nil should be legal -- and
>>               ^^^^^^^^^^^^
>>
>>This is the crux of the debate.  It seems entirely logical that (CAR
>>'()) and (CAR NIL) should be legal - and return NIL - if (EQ NIL '())
>>is true.  But IMHO (EQ NIL '()) should be _false_ in any "sane LISPs".
>>
>....
>>
>>How can muddling the logically distinct types "symbol", "list", and
>>"boolean" be less daft than introducing a needless and
>>counter-productive proliferation of name spaces? :-)
>>
>OK, there *is* a point here, but not one I have any difficulty with.
>Infinity, zero and the empty set all have paradoxical properties: that's
>one of the things that happens at limits. The empty list is a limit.
>Hence it behaves in odd ways. If you want to use a different value for
>false, that's easy:
>
>(setq false '())
>
>
>
>-- 
>    .::;====r==\              ····@uk.co.exnet (Simon Brooke)
>   /  /____||___\____         MS Windows IS an operating environment.      
>  //==\   ~||~  |  /__\(      C++ IS an object oriented programming language. 
> //____\___||___|_//  \|:     Citroen 2cv6 IS a four door family saloon.


Much better, from a theoretical viewpoint, is the more "radical"
approach.  As you say, (CAR '()) represents a limit just as much as (/
1 0).  Both should, in principle, signal an error for the same
reasons.  As for (SETQ FALSE '()), that misses the point entirely.
The main historical reason for deliberately confusing the empty list
and boolean false is to support hacks like the return value of MEMBER
being used most frequently as a boolean, but also returning a
non-empty list which is useful in its own right when it returns "true"
- thus the convention of the empty list being "false" and anything
else being "true".  "Besides," the reasoning probably went, "we
already have this perfectly good pre-defined constant, NIL, why not
let it do double duty?"  Not a very good argument, but the kind likely
to prevail in the experimental mood in which lisp was originally
implemented and in which it has primarily evolved.  I doubt anyone can
supply any particularly compelling theoretical grounds for
perpetuating the multiple meanings of NIL.  There are any number of
practical grounds, however, mainly due to the volumes of Lisp source
code that would suddenly break if the assumption that NIL, '(), and
boolean false were all EQ were made untrue.  A strict interpretation
of the Scheme standard requires one to bite that particular bullet,
but it is not surprising that the Common Lisp committee, for example,
was unwilling to do so.

------------------------------------------------------------
Kirk Rader                                 ····@triple-i.com
From: Bill Gooch on SWIM project x7151
Subject: Re: Nil Question
Date: 
Message-ID: <2vi2cn$k3r@pulitzer.eng.sematech.org>
In article <··········@triple-i.com>, ····@triple-i.com (Kirk Rader) writes:
|> 
|> This is the crux of the debate.  It seems entirely logical that (CAR
|> '()) and (CAR NIL) should be legal - and return NIL - if (EQ NIL '())
|> is true.  But IMHO (EQ NIL '()) should be _false_ in any "sane LISPs".

NIL is a symbol whose value is '().  If you do not want NIL's value to 
be '(), then what value do you have in mind for it?

|> As I am sure you know, in dialects such as Scheme NIL is a symbol and
|> not a list,

In Lisp, NIL is a *symbol* whose *value* is a list (the empty one).

|>... (and not boolean false, for that matter) 

This is a separate issue, about which there is reason for discussion.
It turns out that '() being considered false is very convenient in Lisp
practice, although in principle it might not make a lot of sense for 
boolean false and the empty list to be the same thing.  I think this
EQness and its usage also makes Lisp a bit harder to learn at first.

The tradeoff here has been pretty clearly illuminated for me since I 
started working in Smalltalk, where nil and false are entirely distinct.
The same conditional logic often takes more code to produce in Smalltalk
than in Lisp, but the result is also often easier to read and understand
(at least for those who are not yet very fluent in Lisp).  In Smalltalk
you say "bar mumble notNil ifTrue: [bar frotz]" where in Lisp you would 
say (if (mumble bar) (frotz bar)).

|>...
|> How can muddling the logically distinct types "symbol", "list", and

Not to belabor the point, but again: the Lisp definition of NIL does
not muddle the types symbol and list.  It is a specific use of these 
types that is entirely consistent with the rest of the language.

|> "boolean" be less daft than introducing a needless and
|> counter-productive proliferation of name spaces? :-)

I'm not sure what the last phrase refers to.  Perhaps I missed a previous
reference to proliferation of namespaces?
From: Kirk Rader
Subject: Re: Nil Question
Date: 
Message-ID: <CsMw14.Ln1@triple-i.com>
In article <··········@pulitzer.eng.sematech.org> ··········@sematech.org (Bill Gooch) writes:
>
>In article <··········@triple-i.com>, ····@triple-i.com (Kirk Rader) writes:
>|> 
>|> This is the crux of the debate.  It seems entirely logical that (CAR
>|> '()) and (CAR NIL) should be legal - and return NIL - if (EQ NIL '())
>|> is true.  But IMHO (EQ NIL '()) should be _false_ in any "sane LISPs".
>
>NIL is a symbol whose value is '().  If you do not want NIL's value to 
>be '(), then what value do you have in mind for it?

In a dialect like Scheme which has a separate distinguished object
that is not a symbol to represent '(), there is no special value for
NIL, it is just a symbol (and not a predefined constant.)

>
>|> As I am sure you know, in dialects such as Scheme NIL is a symbol and
>|> not a list,
>
>In Lisp, NIL is a *symbol* whose *value* is a list (the empty one).

There is no such thing as "Lisp" in the sense you mean.  There are
particular dialects like Scheme, Common Lisp, etc.  The majority of
dialects behave like Common Lisp in this regard, i.e.  (AND (EQ NIL
'()) (EQ NIL (NOT T))) does not signal any unbound-variable errors and
evalutes to T.  In a strictly-compliant Scheme, the same form,
assuming that it is evaluated in an environment where T and NIL have
not been defined as global or lexical variables, results in
unbound-variable errors because NIL and T are not constants in that
language.  The Scheme equivalent, (AND (EQ #F '()) (EQ #F (NOT #T))),
evaluates to #F because (EQ #F '()) evalutes to #F.  Similarly
(SYMBOL? #F) evaluates to #F, since #F is not a symbol (nor is there
any particular value that boolean false should _be_ a symbol, NIL or
any other.)  Mutatis mutandis for (LIST? #f).

>
>|>... (and not boolean false, for that matter) 
>
>This is a separate issue, about which there is reason for discussion.
>It turns out that '() being considered false is very convenient in Lisp
>practice, although in principle it might not make a lot of sense for 
>boolean false and the empty list to be the same thing.  I think this
>EQness and its usage also makes Lisp a bit harder to learn at first.
>
>The tradeoff here has been pretty clearly illuminated for me since I 
>started working in Smalltalk, where nil and false are entirely distinct.
>The same conditional logic often takes more code to produce in Smalltalk
>than in Lisp, but the result is also often easier to read and understand
>(at least for those who are not yet very fluent in Lisp).  In Smalltalk
>you say "bar mumble notNil ifTrue: [bar frotz]" where in Lisp you would 
>say (if (mumble bar) (frotz bar)).
>

Ample experience in dialects where the distinction is made has shown
that the "convenience" mainly stems from backwards (or sidewards)
compatibility with other dialects where the distinction is not made.
Is (IF (NULL? (MUMBLE BAR)) #F (FROTZ BAR)) really enough more labor
to write or comprehend to justify the presence or absence of a major
language feature?

>|>...
>|> How can muddling the logically distinct types "symbol", "list", and
>
>Not to belabor the point, but again: the Lisp definition of NIL does
>not muddle the types symbol and list.  It is a specific use of these 
>types that is entirely consistent with the rest of the language.

Change that to "entirely consistent with the rest of Common Lisp (or
whatever other particular dialect)" and we will _almost_ agree. :-) My
point was never that a lisp can't be made to work where NIL is a
predefined constant with multiple meanings - just that there is little
conceptual merit in the practice and the only major practical merit is
because it has so often been done that way in the past.

>
>|> "boolean" be less daft than introducing a needless and
>|> counter-productive proliferation of name spaces? :-)
>
>I'm not sure what the last phrase refers to.  Perhaps I missed a previous
>reference to proliferation of namespaces?


There was an earlier message to which mine was a reply which
criticized as "daft" any suggestion that a Lisp differ from, for
example, Common Lisp in its treatment of (CAR NIL), but criticized as
only slightly less (or was it sligthly more?) "daft" that a Lisp
employ a Common Lisp-like distinction between the "value cell" and the
"function cell" of a symbol - i.e. that functions should exist in a
separate name space from variables.  For the record, Scheme makes no
such distinction - the object in the function position of a form is
evaled just like any other.

------------------------------------------------------------
Kirk Rader                                 ····@triple-i.com
From: Bill Gooch on SWIM project x7151
Subject: Re: Nil Question
Date: 
Message-ID: <2vrubn$f3c@pulitzer.eng.sematech.org>
In article <··········@triple-i.com>, ····@triple-i.com (Kirk Rader) writes:
|> In article <··········@pulitzer.eng.sematech.org> ··········@sematech.org (Bill Gooch) writes:
|> >
|> >In Lisp, NIL is a *symbol* whose *value* is a list (the empty one).
|> 
|> There is no such thing as "Lisp" in the sense you mean.

Excuse me?  I was referring to Common Lisp or any of a number
of other dialects - but I'm sure you knew that.  I think the 
context of our discussion made it abundantly clear that I was
not referring to Scheme.

|> >|>... (and not boolean false, for that matter) 
|> >....
|> >The tradeoff here has been pretty clearly illuminated for me since I 
|> >started working in Smalltalk, where nil and false are entirely distinct.
|> >....  In Smalltalk
|> >you say "bar mumble notNil ifTrue: [bar frotz]" where in Lisp you would 
|> >say (if (mumble bar) (frotz bar)).
|> 
|> Ample experience in dialects where the distinction is made has shown
|> that the "convenience" mainly stems from backwards (or sidewards)
|> compatibility with other dialects where the distinction is not made.
|> Is (IF (NULL? (MUMBLE BAR)) #F (FROTZ BAR)) really enough more labor
|> to write or comprehend to justify the presence or absence of a major
|> language feature?

I was not arguing for nor against the decisions made long ago by
other people in this regard.  Frankly, I don't consider it all that 
important, and I don't quite understand why you (apparently) do,
unless it is strictly a matter of principle.  I tend not to feel
very strongly about language issues which have are of little or no
practical significance.  In other words, I would be happy to work
with the Scheme approach, but I have nothing against the way this 
is dealt with in CL.

|> .... My
|> point was never that a lisp can't be made to work where NIL is a
|> predefined constant with multiple meanings - just that there is little
|> conceptual merit in the practice and the only major practical merit is
|> because it has so often been done that way in the past.

I don't believe in too much backward compatibility - the bane of 
Interlisp IMHO - but in this case that may be a very good reason for 
NIL being the way it is in CL.
From: Barry Margolin
Subject: Re: Nil Question
Date: 
Message-ID: <2vn5dcINN96u@early-bird.think.com>
In article <··········@pulitzer.eng.sematech.org> ··········@sematech.org (Bill Gooch) writes:
>In Lisp, NIL is a *symbol* whose *value* is a list (the empty one).

NIL is much more special than that.  It's a special object that is both a
symbol and a list.  Its value is itself.  Try these in most Lisps (I know
they work in Common Lisp and GNU Emacs Lisp (except the last, since Emacs
doesn't have typep)):

(eq 'nil '()) => T

(eq nil 'nil) => T

(typep 'nil 'list) => T
-- 
Barry Margolin
System Manager, Thinking Machines Corp.

······@think.com          {uunet,harvard}!think!barmar
From: Bill Gooch on SWIM project x7151
Subject: Re: Nil Question
Date: 
Message-ID: <2vuu3r$apc@pulitzer.eng.sematech.org>
In article <············@early-bird.think.com>, ······@think.com (Barry Margolin) writes:
|> In article <··········@pulitzer.eng.sematech.org> ··········@sematech.org (Bill Gooch) writes:
|> >In Lisp, NIL is a *symbol* whose *value* is a list (the empty one).
|> 
|> NIL is much more special than that.  It's a special object that is both a
|> symbol and a list.  Its value is itself.

Silly me - I stand corrected.
From: D. V. Henkel-Wallace
Subject: Nil Question
Date: 
Message-ID: <GUMBY.94Jun27144039@rtl.cygnus.com>
   Date: Sat, 25 Jun 1994 23:13:48 GMT
   From: ······@netcom.com (Henry G. Baker)

   In article <················@netcom.com> ······@netcom.com (David Pollen) writes:
   >While is Nil an Atom, and why do first rest and second applied to it
   >return Nil instead of some sort of error?
   >
   >What is the reasoning by the creators of the language for this?

   I seem to recall that MIT Lisp (Maclisp) _did_ give you an error on
   this.

  For amusement value, check this out (from the '78 Moonual):

  car	SWITCH
  cdr	SWITCH

  Officially car and cdr are only applicable to lists.  However, as a
  metter of convenience the car and cdr of nil are nil.  This allows
  programs to car and cdr off the ends of lists without having to check,
  which is sometimes helpful.  Furthermore, some old programs apply car
  and cdr to objects other than lists in order to hack with the internal
  representation.  To provide control over this, the value of car can be
  set to control which data types are subject to the car operation.
  Similarly, the value of cdr controls the cdr operation.  Illegal
  operations will cause errors.  For reasons of efficiency, this error
  checking is only enabled in (*rset t) more and is mostly turned off in
  compiled programs.  The values to which the switches may be set are:

  Value		Operation applicable to
  list		lists.
  nil		lists and nil
  symbol	lists, nil and symbols
  t		anything.

  The default value of the switches is nil.

I once tried to set this to 'list -- macsyma refused to work.  

I believe that once upon a time car of a symbol was the pname and the
cdr the plist (this was before function or value cells, and well
before _my_ time).  
From: Neves
Subject: Re: Nil Question
Date: 
Message-ID: <2upebh$57e@anaxagoras.ils.nwu.edu>
D. V. Henkel-Wallace (·····@rtl.cygnus.com) wrote:
: I believe that once upon a time car of a symbol was the pname and the
: cdr the plist (this was before function or value cells, and well
: before _my_ time).  

In Lisp 1.5 the CAR of a symbol was always -1.  The CDR held the plist
where the PNAME and other symbol information could be found.  I
believe Stanford's Lisp 1.6 also used that convention but I tossed my
1.6 manual long ago.

In those dynamic days plists meant something.  You could also set NIL
to something non-nil :-)
-David
From: Chris Riesbeck
Subject: Re: Nil Question
Date: 
Message-ID: <2uppo2$6pi@anaxagoras.ils.nwu.edu>
In article <··········@anaxagoras.ils.nwu.edu>, ·····@aristotle.ils.nwu.edu (Neves ) writes:
> 
> In Lisp 1.5 the CAR of a symbol was always -1.  The CDR held the plist
> where the PNAME and other symbol information could be found.  I
> believe Stanford's Lisp 1.6 also used that convention but I tossed my
> 1.6 manual long ago.
> 
> In those dynamic days plists meant something.  You could also set NIL
> to something non-nil :-)

Better than that, in UCI Lisp you could set the CAR of a symbol to
something other than -1, thereby turning a symbol into a list. 

If you changed the CAR of FOO to BAZ, where BAZ was a FEXPR (ah, the
days when users could define their own special forms), then whenever
Lisp read the atom FOO it would "see" the list (BAZ ...) and call BAZ.

For some reason, the Common Lisp committee didn't consider this an
important feature to preserve :-)
From: Henry G. Baker
Subject: Re: Nil Question
Date: 
Message-ID: <hbakerCs4vz2.79I@netcom.com>
In article <··········@anaxagoras.ils.nwu.edu> ·····@aristotle.ils.nwu.edu (Neves ) writes:
>D. V. Henkel-Wallace (·····@rtl.cygnus.com) wrote:
>: I believe that once upon a time car of a symbol was the pname and the
>: cdr the plist (this was before function or value cells, and well
>: before _my_ time).  
>
>In Lisp 1.5 the CAR of a symbol was always -1.  The CDR held the plist
>where the PNAME and other symbol information could be found.  I
>believe Stanford's Lisp 1.6 also used that convention but I tossed my
>1.6 manual long ago.
>
>In those dynamic days plists meant something.  You could also set NIL
>to something non-nil :-)

This has absolutely nothing (nil?) to do with the discussion, but I seem
to recall that Howard I. Cannon (HIC) ex-Symbolics, ex-MIT, used to have
the vanity license plate of 'CDR' on his car...  (HIC, of Flavors fame)
From: ······@DELPHI.COM
Subject: Re: Nil Question
Date: 
Message-ID: <2urhsb$bb6@news.delphi.com>
·····@aristotle.ils.nwu.edu (Neves ) writes:

>D. V. Henkel-Wallace (·····@rtl.cygnus.com) wrote:
>: I believe that once upon a time car of a symbol was the pname and the
>: cdr the plist (this was before function or value cells, and well
>: before _my_ time).  

>In Lisp 1.5 the CAR of a symbol was always -1.  The CDR held the plist
>where the PNAME and other symbol information could be found.  I
>believe Stanford's Lisp 1.6 also used that convention but I tossed my
>1.6 manual long ago.

I remember reverse engineering someone else's  Lisp 1.6 code and after
careful tracing finding that they had reduced a data structure to NIL,
then took the CAR.  Made no sense until two lines later where they did
(EQ funny_result (CAR NIL)).  Chased down the author to ask "why?" and
got the response that he'd found that (CAR NIL) was a fixed, unique value
which was very unlikely to be derived any other way, so he used it as
a touchstone.  (CAR NIL) was different than (CAR any_other_atom), so 
it was apparently not -1.

>In those dynamic days plists meant something.  You could also set NIL
>to something non-nil :-)
>-David

T was always a popular value.  Tended to confuse the interpreter, though.

Bob Bechtel
From: Mark McConnell
Subject: Re: Nil Question
Date: 
Message-ID: <2umo7a$2oh@coils.cims.nyu.edu>
In article <················@netcom.com>
······@netcom.com (David Pollen) writes:
>While is Nil an Atom, and why do first rest and second applied to it
>return Nil instead of some sort of error?

In Common Lisp, nil is both an atom and a list, namely the empty list
'() .  It is the only object that is both.  When you apply first (=
car) and second (= cadr), you get the results of applying these
functions to a list, not to an atom.

A harder question is why calling for the car and cdr of an empty list
should return an empty list, and not be an error.  What is the first
element of the list that has no elements?  This may not be as
nonsensical as it sounds.  For instance,

Theorem: Every element of the empty set is blue.

Proof (Glen Whitney): Assume the contrary.  Then there is an element
of the empty set which is not blue.  But the empty set has no
elements, contradiction.  QED

So (car '()) simply returns the first blue element of '() , which is '()
:-) .  If you buy that, then (cdr '()) must be '() , since the empty
set minus the empty set is the empty set.

(By the way, the theorem really is correct.  It's a conditional of the
form A ==> B , where A is "x is an element of the empty set" and B is
"x is blue".  In any conditional A ==> B where A is false, the whole
conditional is automatically true, no matter what the truth value of B
is.)

If I remember the history, nil was the same as '() in the first Lisp
that McCarthy was using, where car stood for "contents of the address
register" (the left half of a machine word) and cdr for "contents of
the decrement register" (right half of a word).  The way they were
coding nil happened to be the same as the empty list.  They soon
discovered this identity was a valuable feature.  For instance,
(member 'c '(a b c d)) can return the partial list (c d) , and
(member 'e '(a b c d)) can return the _partial list_ '() .  At first
you wonder why the latter should have anything to do with the boolean
value "false"; then you see why the feature is useful.
From: Kirk Rader
Subject: Re: Nil Question
Date: 
Message-ID: <Cs41vM.J7D@triple-i.com>
In article <··········@coils.cims.nyu.edu> ········@coils.cims.nyu.edu (Mark McConnell) writes:

   ...

>
>A harder question is why calling for the car and cdr of an empty list
>should return an empty list, and not be an error.  What is the first
>element of the list that has no elements?  This may not be as
>nonsensical as it sounds.  For instance,
>
>Theorem: Every element of the empty set is blue.
>
>Proof (Glen Whitney): Assume the contrary.  Then there is an element
>of the empty set which is not blue.  But the empty set has no
>elements, contradiction.  QED
>
>So (car '()) simply returns the first blue element of '() , which is '()
>:-) .  If you buy that, then (cdr '()) must be '() , since the empty
>set minus the empty set is the empty set.
>
>(By the way, the theorem really is correct.  It's a conditional of the
>form A ==> B , where A is "x is an element of the empty set" and B is
>"x is blue".  In any conditional A ==> B where A is false, the whole
>conditional is automatically true, no matter what the truth value of B
>is.)
>

The theorem is correct, but what does it have to do with "(car '())"?
If one wants to employ strained analogies to symbolic logic, perhaps a
better fit would be Russell's (or was it Frege's?  It's been a while!)
approach to the problem of improper definite description, i.e. choose
"nil" as the entity referred to by improper definite descriptions and
define "(car x)" as "iota y :: y is the first element of x".  Since
the given predicate is true of no objects when "'()" is substituted
for "x", the definite description refers to the chosen object, which
we already defined to be "nil".

But the real answer to the original question is, of course, that
Common Lisp defines "nil" to be the same as "'()" and for "(car nil)"
to return "nil" for the historical and convenience reasons that you
and others have cited, not for any deep theoretical reasons.  Other
lisp dialects, notably Scheme, have done things otherwise.
From: Jim McDonald
Subject: Re: Nil Question
Date: 
Message-ID: <1994Jun28.222406.8247@kestrel.edu>
Perhaps a more systematic way to look at this is just that 
in Common Lisp, NIL has been overloaded for several notions:

  The symbol whose name is "NIL" 
  The empty list
  Boolean false
  Undefined (or bottom) 

One can argue that a cleaner design would make all four of these
distinct.  A fifth notion, ill-typed forms such as (car 'foo),
can be dealt with separately, via typecheckers or runtime
errors.

Further, UNDEFINED could be extended to be some kind of 
structure or a family of things, encoding information about
the kind of undefinedness (0/0, car of an empty list, etc.).
The essential idea is that each partial algebraic operation
can be extended to be complete by inventing new things to
represent the results for exceptional cases.

I use a typed language called REFINE (built on top of lisp) which
has one distinguished constant called UNDEFINED, with predicates
to test for it, etc.  It's pretty handy, but you have to learn
to watch out for undefined as an argument, e.g. "if x then foo()"
will execute foo if x is undefined, because undefined is not
false.  (That's a pragmatic choice: other languages chould use
different semantics for undefined wrt conditional tests or 
clauses.)

In Refine, first of an empty sequence or arb of an empty set
returns undefined.  First of a symbol won't typecheck, so that's 
not an issue unless you manage to circumvent typechecking, in 
which case you may get some random runtime error.



-- 
James McDonald
Kestrel Institute                       ········@kestrel.edu
3260 Hillview Ave.                      (415) 493-6871 ext. 339
Palo Alto, CA 94304                fax: (415) 424-1807