Earlier quoted context omitted.
The former is somewhat reasonable for having pi denote 3.14159... and such. It brings in its own difficulties. If nil is a variable/constant which evaluates to some nil object, then to talk about nil itself, we have to quote it. The object which it denotes doesn't print as nil; it has its own printed rep like () and we will end up seeing that printed rep and using it. So then we have two nil representations to deal w…
> 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 o…
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:
(cdr (assq key a-list))
rather than (let ((val (assq key a-list)))
(cond ((not (null? val)) (cdr val))
(else nil)))