| > to talk about nil itself, we have to quote it. So? That's no different than if you want to talk about 'pi rather than pi a.k.a. 3.14159... > So then we have two nil representations to deal with No different than "pi" and "3.14159". > If () isn't self-evaluating (like the criminally stupid design in Scheme), we have to quote it: '(). I agree, () should be self-evaluating just like numbers and vectors. The behavior of () should be analogous to the behavior of 0 or 0.0 or #() or "". > If we have additional semantic roles for () like it being Boolean false And why would you want to do a stupid thing like that? > The list terminator is de facto a symbol because it's exploited for its identity First, the list terminator need not be the same thing as the empty list. The list terminator is an implementation thing. The empty list is a language-semantics thing. These need not be the same. Second, neither of these need to be unique. There can be multiple list terminators, and there can be multiple empty lists, just as there can be multiple empty vectors and multiple empty strings and even multiple instances of the same number (which actually happens with bignums). > we care whether the cdr of a cons is or is not nil No, what we care about -- or at least what we should care about -- is whether the CDR of a cons is an (n.b. not the) empty list. (eq #() #()) need not be true (in fact, generally isn't). Why should (eq () ()) be any different? And BTW under no circumstances should taking the CAR or CDR of an empty list do anything other than signal an error. |
No it doesn't, but that choice happens to give us a compact recursive definition.
> There can be multiple list terminators ... multiple empty lists ...
Sure, and 2022 can be written MMXXII, and whatnot.
Mathematically, there is one empty list, so why proliferate it?
There can be multiple empty strings which is useful if strings are mutable. If strings are immutable, it's silly to have more than one empty string.
The empty list is immutable, so ...
> under no circumstances should taking the CAR or CDR of an empty list do anything other than signal an error.
Lisp 1 and 1.5 had it that way, certainly. It's mostly just inconvenient. A good mix is to have strict vectors and strings which signal on out-of-bounds, but lists which are forgiving. Forgiving lists allow good old Ashwin Ram to have:
rather than