Skip to content

LISP - `some` 函数

some 函数是一个强大的序列谓词,用于确定一个或多个序列中是否至少有一个元素满足给定条件。它效率很高,因为一旦找到匹配项便会停止处理并返回。

(some predicate sequence &rest more-sequences)
  • predicate:一个函数,接受与所提供序列数量相同的参数。对于匹配项,它应返回一个非nil值;否则返回nil。
  • sequence:要迭代的第一个序列(列表、向量或字符串)。

这非常重要:some 不仅仅返回 T(真)。它返回谓词返回的第一个非nil值。如果谓词在检查所有元素后从未返回非nil值,some 将返回 nil(假)。

让我们检查一个列表是否包含任何偶数。

(let ((list1 '(1 3 5 8 9))
(list2 '(1 3 5 7 9)))
;; 谓词 `evenp` 对 8 返回 T。`some` 停止并返回 T。
(print (some #'evenp list1)) ;=> T
;; 没有元素满足 `evenp`,因此 `some` 返回 NIL。
(print (some #'evenp list2)) ;=> NIL
)
T
NIL

在这里,我们将检查字符串中的第一个元音。谓词使用 member,它返回从找到的元素开始的子列表——一个非nil值。

(defun find-first-vowel (s)
(some #'(lambda (char)
(member char '(#\a #\e #\i #\o #\u)))
s))
(let ((result1 (find-first-vowel "rhythm"))
(result2 (find-first-vowel "lisp-is-fun")))
;; 没有元音,因此谓词始终返回 NIL。
(format t "Vowel found in 'rhythm': ~a~%" result1) ;=> NIL
;; 第一个元音是 'i'。`member` 返回 `(#\i #\o #\u)`。
;; `some` 停止并返回此列表。
(format t "Vowel found in 'lisp-is-fun': ~a~%" result2) ;=> (#\I #\O #\U)
)
Vowel found in 'rhythm': NIL
Vowel found in 'lisp-is-fun': (#\I #\O #\U)

当你提供多个序列时,谓词在每一步都会从每个序列中接收一个元素。当最短的序列耗尽时,迭代停止。

;; 检查 list1 中是否有任何元素大于 list2 中的对应元素
(let ((list-a '(1 5 3))
(list-b '(2 4 6)))
;; 1>2 为 nil。5>4 为 T。`some` 停止并返回 T。
(print (some #'> list-a list-b)) ;=> T
)
(let ((list-c '(1 2 3))
(list-d '(4 5 6)))
;; 所有比较都返回 nil,所以最终结果是 NIL。
(print (some #'> list-c list-d)) ;=> NIL
)
T
NIL

some 非常适合简洁地表达“存在”或“至少一个”的条件:

  • 验证:检查任何提交的数据字段是否包含无效字符。(some #'invalid-char-p user-input)
  • 搜索:快速确定产品列表是否包含任何在售商品。(some #'on-sale-p products)
  • 状态检查:在游戏中,检查列表中是否有任何敌人在攻击范围内。(some #'in-range-p enemies)

some 属于序列谓词家族的一部分:

  • some:是否存在至少一个真结果?
  • every:是否所有结果都为真?
  • notany:是否存在任何真结果?(是否所有结果都为假?)
  • notevery:是否存在至少一个假结果?