Why does (nil . nil) evaluate to (nil) instead of just nil in SBCL?
This behavior is not specific to SBCL; it's defined in the Common Lisp standard and applies to all compliant implementations.
In Common Lisp, the empty list is represented by the symbol NIL
or an empty pair of parentheses ()
. They are the same object, as can be verified with (eq 'nil '())
, which returns T
.
'NIL
is not a cons cell, cons cells are data structures that form linked lists in Common Lisp, it's a special value that represents the empty list. The CAR
and CDR
functions, used to access the first and rest of a cons cell respectively, are defined to return NIL
when given NIL
as an argument. This is a special case to ensure consistent behavior when working with lists.
The dotted pair notation, (NIL . NIL)
, is a way to represent a cons cell where both the CAR
and CDR
are NIL
. However, this notation is equivalent to (NIL)
in Common Lisp, as the trailing NIL
is omitted when printing or evaluating the cons cell.
The following examples illustrate this behavior:
(car '()) == '()
(cdr '()) => NIL
Here, (car '())
and (cdr '())
return NIL
because they are called with an empty list, which is represented by '()
.
(car '(NIL . NIL)) => NIL
(cdr '(NIL . NIL)) => NIL
In this case, (car '(NIL . NIL))
and (cdr '(NIL . NIL))
also return NIL
because '(NIL . NIL)
is equivalent to (NIL)
, which is an empty list.
To summarize, (NIL . NIL)
evaluates to (NIL)
in Common Lisp because the dotted pair notation is a way to represent a cons cell where both the CAR
and CDR
are NIL
, but this representation is equivalent to the empty list NIL
.