admin管理员组

文章数量:1122833

Global variable a is a cons cell, but NOT a list. Why does LISTP return T for it?

* (defvar a (cons 1 2))
A
* a
(1 . 2)
* (listp a)
T

Edit: Thanks to Gwang-Jin Kim for a function to substitute for what I wanted:

(defun proper-list-p (lst)
  (or (null lst)                           ; either a `'()` or:
      (and (and (consp lst)                ; a cons
                (listp (cdr lst)))         ; a cons that has a cons cell or null as CDR
           (null (cdr (last lst)))         ; not a dotted list
           (not (tailp lst (cdr lst))))))  ; not circular

Global variable a is a cons cell, but NOT a list. Why does LISTP return T for it?

* (defvar a (cons 1 2))
A
* a
(1 . 2)
* (listp a)
T

Edit: Thanks to Gwang-Jin Kim for a function to substitute for what I wanted:

(defun proper-list-p (lst)
  (or (null lst)                           ; either a `'()` or:
      (and (and (consp lst)                ; a cons
                (listp (cdr lst)))         ; a cons that has a cons cell or null as CDR
           (null (cdr (last lst)))         ; not a dotted list
           (not (tailp lst (cdr lst))))))  ; not circular
Share Improve this question edited Nov 30, 2024 at 15:56 Scooter asked Nov 21, 2024 at 17:22 ScooterScooter 7,0618 gold badges44 silver badges72 bronze badges 1
  • 3 (cons 1 2) is a list; it's just not a proper list - which is not what listp is checking for. All it does is distinguish between a cons cell and an atom. – jasonharper Commented Nov 21, 2024 at 17:34
Add a comment  | 

2 Answers 2

Reset to default 3

From CLHS

Returns true if object is of type list; otherwise, returns false.

and the definition of the type list is:

The types cons and null form an exhaustive partition of the type list.

Since (1 . 2) is a cons, it's also a list.

(listp object) == (typep object 'list) == (typep object '(or cons null))

For efficiency, listp doesn't try to determine if it's a proper list, which ends with NIL. There's no standard function that does this. See Check for proper list in Common Lisp

The listp doesn't check whether it is a proper list or not (with last element of the conses being NIL).

(Incorrect!!) To check for a proper list:

(defun proper-list-p (lst)
  (or (null lst)                           ; either a `'()` or:
      (and (consp lst)                     ; a cons
           (not (tailp lst (cdr lst)))     ; not circular
           (null (cdr (last lst))))))      ; not a dotted list

As @Scooter pointed out, the tailp test needs to be pretested for the case that (cdr lst) is not a list/cons. Then (proper-list-p (cons 1 2)) doesn't throw an error which tailp throws when testing a tail which is a non-nil atom! So this is the final, correct version:

(defun proper-list-p (lst)
  (or (null lst)                           ; either a `'()` or:
      (and (consp lst)                     ; a cons
           (and                            ; not circular:
            (listp (cdr lst))              ; - evade tailp error
            (not (tailp lst (cdr lst))))   ; - test non-circularity
           (null (cdr (last lst))))))      ; not a dotted list

Now, we get:

(proper-list-p '())          ;; => T
(proper-list-p (cons 1 2))   ;; => NIL
(proper-list-p 1)            ;; => NIL (any non-nil atom)
(proper-list-p (list 1 2 3)) ;; => T

本文标签: predicateWhy does listp in SBCL Common Lisp return T for a nonlist cons cellStack Overflow