LISP - 列表谓词
现代 Lisp:列表谓词
Section titled “现代 Lisp:列表谓词”谓词是测试条件并返回布尔值的函数。在 Common Lisp 中,标准的假值为 NIL,任何其他值都被视为真。列表谓词是检查和验证列表结构的重要工具,构成了安全且健壮的列表处理代码的基础。
核心结构谓词:listp、consp、null
Section titled “核心结构谓词:listp、consp、null”这三个谓词是检查类列表数据性质的基础。理解它们的区别,特别是关于空列表 NIL 的区别,至关重要。
| 谓词 | 回答的问题 | 对…返回 T | 关键行为 |
|---|---|---|---|
listp | “这是一个恰当的列表吗?” | '(a b c),NIL(空列表) | 最通用的列表检查器。(listp nil) 返回 T。 |
consp | “这是一个 cons 单元格吗?” | '(a b c),'(a . b) | 检查非空列表结构。(consp nil) 返回 NIL,因为 NIL 不是 cons 单元格。 |
null | “这是空列表吗?” | NIL,'() | 检查空列表 NIL 的标准方法。它是 consp 的逆操作。 |
示例:比较结构谓词
Section titled “示例:比较结构谓词”(let ((proper-list '(1 2 3)) (dotted-list '(a . b)) (empty-list nil) (atom 'x)) (format t "~12a | listp: ~a, consp: ~a, null: ~a~%" "Proper List" (listp proper-list) (consp proper-list) (null proper-list)) (format t "~12a | listp: ~a, consp: ~a, null: ~a~%" "Dotted List" (listp dotted-list) (consp dotted-list) (null dotted-list)) (format t "~12a | listp: ~a, consp: ~a, null: ~a~%" "Empty List" (listp empty-list) (consp empty-list) (null empty-list)) (format t "~12a | listp: ~a, consp: ~a, null: ~a~%" "Atom" (listp atom) (consp atom) (null atom)))Proper List | listp: T, consp: T, null: NILDotted List | listp: T, consp: T, null: NILEmpty List | listp: T, consp: NIL, null: TAtom | listp: NIL, consp: NIL, null: NIL元素和关联谓词
Section titled “元素和关联谓词”member - 检查元素是否存在
Section titled “member - 检查元素是否存在”member 检查列表中是否存在某个元素。如果找到,它将返回从该元素首次出现位置开始的子列表(一个真值)。如果未找到,则返回 NIL。
- 返回值:请记住,
member返回的是列表的尾部,而不仅仅是T。 - 相等性测试:默认情况下,
member使用#'eql。您可以使用:test关键字指定不同的比较函数,例如使用#'equal来比较结构。
(let ((my-list '(a b c b d))) (format t "Is 'b in the list? ~a~%" (member 'b my-list)) ; -> (B C B D) (format t "Is 'z in the list? ~a~%" (member 'z my-list))) ; -> NIL
(let ((nested-list '((x 1) (y 2) (z 3)))) ;; #'eql(默认)无法找到结构相似的列表 (format t "Find (y 2) with #'eql? ~a~%" (member '(y 2) nested-list)) ;; #'equal 成功 (format t "Find (y 2) with #'equal? ~a~%" (member '(y 2) nested-list :test #'equal)))Is 'b in the list? (B C B D)Is 'z in the list? NILFind (y 2) with #'eql? NILFind (y 2) with #'equal? ((Y 2) (Z 3))assoc - 在关联列表中查找键
Section titled “assoc - 在关联列表中查找键”assoc(关联)用于搜索关联列表(alist),它是一个键值对的列表。如果找到键,它将返回整个键值对。否则,返回 NIL。
(let ((config '((:user . "admin") (:port . 8080) (:debug . t)))) (format t "Port setting: ~a~%" (assoc :port config)) ; -> (:PORT . 8080) (format t "Host setting: ~a~%" (assoc :host config)) ; -> NIL
;; 要仅获取值,请结合 `cdr` 使用 (let ((port-pair (assoc :port config))) (if port-pair (format t "Port value: ~a~%" (cdr port-pair)) ; -> 8080 (format t "Port not found.~%"))))Port setting: (:PORT . 8080)Host setting: NILPort value: 8080循环终止:endp
Section titled “循环终止:endp”endp 是一个通用谓词,用于检查列表是否已到达末尾。如果其参数为 NIL,则返回 T,否则返回 NIL。它相对于 null 的主要优势在于,如果给定非列表参数,它会发出错误信号,这使其成为终止递归函数或预期列表的循环的更安全选择。
示例:安全的递归函数
Section titled “示例:安全的递归函数”(defun count-elements (lst) "使用 `endp` 安全地计数列表中的元素。" (if (endp lst) 0 (1+ (count-elements (rest lst)))))
(format t "Count for '(a b c): ~a~%" (count-elements '(a b c))) ; -> 3(format t "Count for nil: ~a~%" (count-elements nil)) ; -> 0
;; (count-elements 'not-a-list) ; 这将正确地发出错误信号。Count for '(a b c): 3Count for nil: 0