Skip to main content

endp

endp Function

Syntax:

endp list → generalized-boolean

Arguments and Values:

list—a list, which might be a dotted list or a circular list.

generalized-boolean—a generalized boolean.

Description:

Returns true if list is the empty list. Returns false if list is a cons.

Examples:

(endp nil) → true 
(endp(1 2)) → false
(endp (cddr(1 2))) → true

Exceptional Situations:

Should signal an error of type type-error if list is not a list.

Notes:

The purpose of endp is to test for the end of proper list. Since endp does not descend into a cons, it is well-defined to pass it a dotted list. However, if shorter “lists” are iteratively produced by calling cdr on such a dotted list and those “lists” are tested with endp, a situation that has undefined consequences will eventually result when the non-nil atom (which is not in fact a list) finally becomes the argument to endp. Since this is the usual way in which endp is used, it is conservative programming style and consistent with the intent of endp to treat endp as simply a function on proper lists which happens not to enforce an argument type of proper list except when the argument is atomic.

Expanded Reference: endp

Testing for end of a proper list

endp returns true when given NIL (the empty list) and false when given a cons. It is designed for testing termination when iterating over a proper list.

(endp nil)
=> T

(endp '(a b c))
=> NIL

Traversing a list with endp

endp is the preferred predicate for testing list termination in loops and recursive functions, because it signals an error if it encounters a non-list atom (unlike null).

(let ((lst '(10 20 30))
(sum 0))
(do ((tail lst (cdr tail)))
((endp tail) sum)
(incf sum (car tail))))
=> 60

endp checks that the argument is a list

Unlike null, endp should signal a type-error if given something that is neither NIL nor a cons. This makes it a safer choice for iterating proper lists.

(endp '())
=> T

(endp '(x))
=> NIL

;; (endp 42) would signal a TYPE-ERROR

Using endp in recursive list processing

endp works well as the base case check in recursive functions that consume proper lists.

(defun sum-list (lst)
(if (endp lst)
0
(+ (car lst) (sum-list (cdr lst)))))

(sum-list '(1 2 3 4 5))
=> 15

(sum-list '())
=> 0

endp with cddr for pairwise processing

When processing list elements in pairs, endp can test the remaining tail at each step.

(defun pairwise-max (lst)
"Return a list of the max of each consecutive pair."
(if (endp (cdr lst))
nil
(cons (max (first lst) (second lst))
(pairwise-max (cddr lst)))))

(pairwise-max '(3 7 2 9 5 1))
=> (7 9 5)