In Scheme, null refers to the empty list, which is a special, unique object that represents the end of a list. This concept is central to understanding list processing in Scheme and distinguishes it from other Lisp dialects. The empty list is written as the literal '().
The empty list: '()
The empty list, '(), is the value that terminates a proper list. In Scheme, a proper list is either the empty list or a pair whose cdr is a list.
- Literal representation: You can write the empty list directly as
'()in your code. The single quote is important, as()by itself would be interpreted as a procedure call with no arguments, which results in a syntax error. - List termination: The
cdrof the final pair in a proper list is always'(). For example, the list(a b c)is internally represented as a chain of pairs:(a . (b . (c . '()))).
The null? predicate
To check if a value is the empty list, Scheme provides the built-in predicate null?.
-
Syntax:
(null? *obj*) -
Behavior: It returns
#tif obj is the empty list, and#fotherwise. This is the standard and correct way to test for the end of a list in a program. -
Example:scheme
(null? '()) ; => #t (null? '(1 2 3)) ; => #f (null? #f) ; => #fUse code with caution.
Scheme vs. Common Lisp: null and nil
One of the most important distinctions to understand is the difference between Scheme and other Lisp dialects, particularly Common Lisp.
| Feature | Scheme | Common Lisp |
|---|---|---|
| Empty list | A unique, non-boolean object, written as '(). |
Represented by the symbol nil. |
| False value | A unique object, #f. |
The same object as the empty list, nil. |
| Truthiness | Everything that is not #f is considered "truthy," including the empty list '(). |
Only nil is false; everything else is true. |
null identifier |
null is not a standard, built-in identifier. Some implementations, like Racket, define it as an alias for '(). |
A function null exists to test for nil. |
This separation in Scheme is a deliberate design choice to avoid "nil punning," where a single object serves two unrelated purposes (end-of-list and boolean false).
Boolean evaluation of null
Because the empty list '() is distinct from the false value #f, it evaluates differently in a boolean context.
-
In a conditional expression like
(if *test* *consequent* *alternative*),'()is treated as a "truthy" value because it is not#f. -
Therefore,
(if '() "true" "false")will evaluate to"true". -
If you want to check for the empty list in a conditional, you must use the
null?predicate.scheme(define my-list '()) (if (null? my-list) "empty" "not empty") ; => "empty"Use code with caution.
Null pointers and implementation
While from a language perspective, null is the empty list object, its underlying implementation may vary. In some implementations, '() might be a special singleton object that a "null pointer" points to. In others, it might be an immediate, tagged value. Critically, these low-level details do not affect its behavior at the language level. Its purpose remains the same: to terminate a list structure.
Practical implications for list processing
Understanding Scheme's null is vital for writing correct list-processing functions, especially recursive ones. A common recursive pattern for operating on a list looks like this:
(define (list-sum l)
(if (null? l)
0 ; Base case: sum of an empty list is 0
(+ (car l) (list-sum (cdr l))))) ; Recursive step
Use code with caution.
In this example, the null? check correctly identifies the base case for the recursion, stopping when the list is empty. If you were to incorrectly rely on the empty list's "truthiness" in an if expression, your function would fail.