nullschemeempty-listthe-little-schemer

In Scheme, what is the difference between `nil` and `null`?


In "The Little Schemer", null is used to refer to the empty list (). But I also see the empty list referred to as nil in Scheme's Error message, e.g. doing:

(car ())

causes:

Error: Attempt to apply car on nil [car] [1]

Which sounds like it's referring to () as nil.


[1] using replit.com's BiwaScheme Interpreter version 0.6.4


This question is similar to What is the exact difference between null and null in common lisp. It is different because as the answers here point out there are differences between Common Lisp and Scheme in their treatment of nil and null.


Solution

  • I think that what you're seeing is an artifact of history in the error messages.

    In traditional Lisps, nil was both the empty list and boolean false, and was rather special in various other ways (for instance, it was also a symbol, which is very weird).

    So in particular () and nil are the same object in such a Lisp, and (not nil) is true, and (not '()) is also true (and in fact (not ()) is both legal and also true). The predicate for the empty list object is null (perhaps should be nullp but history says it is what it is) and (null nil) is true as is (null '()) and (null ()).

    There are also questions about what (car nil) aka (car '()) aka (car ()) should do. Traditionally the answer was this was fine and (car nil) is nil. This gives you a very neat implementation of nil if you're clever.

    Scheme now does away with all of this punning:

    • there is a unique false object which is #f / #false, which is not the empty list;
    • all other objects, are true, so (not x) is true only for x being #f;
    • there is a unique empty list object, which is (), which is not #f and which is therefore true;
    • the predicate for this object is null?, so (null? '()) is true, but (null? #f) is false;
    • car and cdr of () are errors;
    • nil is just a symbol with no special status in the language at all.

    I don't think that having a name for () is standard, but obviously it might be useful to give it one, and null is fine: Racket does that, for instance.

    So in Scheme, nil is just gone, and the pun between empty lists and boolean false with it.

    But very many people who implement Schemes know that nil is what people call the empty list. So when they write error messages, they write nil when they mean (), because that's what everyone has called () for a very long time.

    And that, I think, is what you are seeing here.