Skip to content

LISP - `notevery` 函数

notevery 函数是一个序列谓词(sequence predicate),它测试序列中至少有一个元素不满足给定测试的条件。它是 every 函数的逻辑否定。

可以这样理解:(every predicate sequence) 询问“每个元素都满足谓词吗?”而 (notevery predicate sequence) 询问“是否存在至少一个元素不满足谓词?”。

逻辑上,(notevery p s) 等同于 (not (every p s))。

(notevery predicate &rest sequences+)
  • predicate:一个函数,接受与序列数量相同的参数,并返回一个布尔值(t 或 nil)。
  • sequences+:一个或多个要测试的序列(列表、向量或字符串)。

如果谓词对至少一个元素(或一组元素)返回 nil,则它返回 t。仅当谓词对所有元素都返回 t 时,它才返回 nil。该函数会短路(short-circuit),这意味着一旦找到第一个不满足测试的元素,它就会停止并返回 t。

这里,notevery 和谓词 #'evenp 一起,检查序列中是否有任何数字不是偶数。

;;; 测试一个只包含偶数的列表
(format t "Is there an odd number in '(2 4 6 8)? ~a~%"
(notevery #'evenp '(2 4 6 8))) ; -> NIL,因为所有都是偶数。
;;; 测试一个只包含偶数的向量
(format t "Is there an odd number in '#(2 4 6 8)? ~a~%"
(notevery #'evenp '#(2 4 6 8))) ; -> NIL,因为所有都是偶数。
;;; 测试一个包含奇数的列表
(format t "Is there an odd number in '(2 4 9 8)? ~a~%"
(notevery #'evenp '(2 4 9 8))) ; -> T,因为 9 不是偶数。
Is there an odd number in '(2 4 6 8)? NIL
Is there an odd number in '#(2 4 6 8)? NIL
Is there an odd number in '(2 4 9 8)? T

您可以使用 lambda 函数来创建更复杂、自定义的谓词。让我们检查列表中是否有任何数字小于或等于 10。

(let ((predicate #'(lambda (x) (> x 10))))
;; 测试一个所有数字都大于 10 的列表
(format t "Is any number in '(11 15 14) not > 10? ~a~%"
(notevery predicate '(11 15 14))) ; -> NIL
;; 测试一个部分数字不大于 10 的列表
(format t "Is any number in '(11 5 14) not > 10? ~a~%"
(notevery predicate '(11 5 14)))); -> T
Is any number in '(11 15 14) not > 10? NIL
Is any number in '(11 5 14) not > 10? T

示例:检查字符串是否包含非字母字符

Section titled “示例:检查字符串是否包含非字母字符”

notevery 也适用于字符串。我们可以检查字符串是否包含任何非字母字符。

;; 检查一个纯字母字符串
(format t "Does 'tutorialspoint' contain any non-alphabetic characters? ~a~%"
(notevery #'alpha-char-p "tutorialspoint")) ; -> NIL
;; 检查一个包含数字的字符串
(format t "Does 'lisp-101' contain any non-alphabetic characters? ~a~%"
(notevery #'alpha-char-p "lisp-101")) ; -> T (在 '-' 处停止)
Does 'tutorialspoint' contain any non-alphabetic characters? NIL
Does 'lisp-101' contain any non-alphabetic characters? T

当给定多个序列时,谓词在每一步接收来自每个序列的一个元素。notevery 将测试谓词是否对任何对应的元素对为假。

;; 检查第一个列表中是否有任何元素不小于第二个列表中对应的元素。
(format t "Is (notevery #'< '(1 2 3) '(4 5 6)) -> ~a~%"
(notevery #'< '(1 2 3) '(4 5 6))) ; -> NIL,因为 1<4、2<5 和 3<6 都为真。
;; 再次检查,但包含一个失败情况。
(format t "Is (notevery #'< '(1 8 3) '(4 5 6)) -> ~a~%"
(notevery #'< '(1 8 3) '(4 5 6))) ; -> T,因为 (not (< 8 5)) 为真。
Is (notevery #'< '(1 2 3) '(4 5 6)) -> NIL
Is (notevery #'< '(1 8 3) '(4 5 6)) -> T

notevery 在您寻找单个失败或无效项的验证和检查中特别有用。

  • 数据验证:检查是否有任何提交的表单字段无效。(notevery #'valid-field-p form-data) 将在存在至少一个错误字段时返回 T。
  • 安全性:确认密码包含至少一个非字母数字字符。(notevery #'alphanumericp "p@ssword1") 返回 T,确认密码符合复杂性规则。
  • 质量控制:查找生产批次中是否有任何项目未能通过质量检查。(notevery #'quality-passed-p batch-items) 在发现缺陷时返回 T。