LISP - 谓词
Lisp - 谓词
Section titled “Lisp - 谓词”在 Common Lisp 中,谓词(predicate)是一种用于测试特定条件的函数。它返回一个真或假的值。Lisp 中一个关键概念是其真值的表示:符号 nil 是唯一的假值,而任何其他值都被认为是真值。按照惯例,符号 t 被用作规范的真值。
谓词函数通常以 -p 或 p 作为后缀命名(‘p’ 代表 ‘predicate’),例如 numberp 或 evenp。
常见谓词类别
Section titled “常见谓词类别”以下是一些最常用的谓词,按其用途分组。
在 Lisp 中,选择正确的相等谓词是一项常见任务。它们在比较其参数的严格程度上有所不同。
| 谓词 | 描述 |
|---|---|
| eq | 如果参数在内存中是完全相同的对象,则返回 t。这是最严格、最快的比较。 |
| eql | 与 eq 类似,但对于相同的数字和字符也返回 t。例如,(eql 5 5) 为 t,但 (eql 5 5.0) 为 nil。 |
| equal | 如果参数在结构上相似,则返回 t。它递归地比较列表和字符串。例如,两个元素相同的不同列表是 equal 的。 |
| equalp | 最宽松的比较。与 equal 类似,但忽略字符串的大小写,并比较不同类型的数字(例如,(equalp 5 5.0) 为 t)。 |
| 谓词 | 描述 |
|---|---|
| atom | 如果参数是原子(即,不是 cons cell/列表),则返回 t。 |
| listp | 如果参数是列表(cons cell 或 nil),则返回 t。 |
| numberp | 如果参数是任何类型的数字,则返回 t。 |
| integerp | 如果参数是整数,则返回 t。 |
| floatp | 如果参数是浮点数,则返回 t。 |
| stringp | 如果参数是字符串,则返回 t。 |
| symbolp | 如果参数是符号,则返回 t。 |
| null | 如果参数是 nil,则返回 t,否则返回 nil。 |
| 谓词 | 描述 |
|---|---|
| zerop | 接受一个数值参数,如果为零则返回 t。 |
| evenp | 接受一个整数参数,如果为偶数则返回 t。 |
| oddp | 接受一个整数参数,如果为奇数则返回 t。 |
| > | 接受一个或多个数字。如果它们严格递减,则返回 t。 |
| < | 接受一个或多个数字。如果它们严格递增,则返回 t。 |
| = | 接受一个或多个数字。如果它们在数值上全部相等,则返回 t。 |
代码示例:谓词的实际应用
Section titled “代码示例:谓词的实际应用”让我们创建一个源文件 main.lisp 来演示这些概念。此示例将突出相等谓词之间的差异,并展示一些常见的类型检查。
main.lisp
Section titled “main.lisp”;;; main.lisp - 演示 Common Lisp 谓词
(defun run-predicate-demos () "运行一系列谓词函数演示。"
(format t "--- 相等谓词演示 ---~%") (let ((list1 (list 'a 'b)) (list2 (list 'a 'b))) (format t "(eq list1 list2) -> ~a (内存中的不同对象)~%" (eq list1 list2)) (format t "(equal list1 list2) -> ~a (结构上等价)~%~%" (equal list1 list2)))
(format t "--- 数值谓词演示 ---~%") (format t "(oddp 7) -> ~a~%" (oddp 7)) (format t "(evenp 10) -> ~a~%" (evenp 10)) (format t "(zerop 0.0) -> ~a~%" (zerop 0.0)) (format t "(= 5 5.0) -> ~a (数值相等)~%" (= 5 5.0)) (format t "(> 10 5 1) -> ~a~%" (> 10 5 1)) (format t "(< 2 4 8) -> ~a~%~%" (< 2 4 8)))
(format t "--- 类型谓词演示 ---~%") (format t "(listp '(1 2 3)) -> ~a~%" (listp '(1 2 3))) (format t "(atom 'my-symbol) -> ~a~%" (atom 'my-symbol)) (format t "(stringp \"Hello\") -> ~a~%" (stringp "Hello")) (format t "(null nil) -> ~a~%" (null nil))))
;; 要运行此代码,请在 Lisp 环境中加载文件并调用 (run-predicate-demos)(run-predicate-demos)当您在 Common Lisp 实现(如 SBCL)中加载并执行此代码时,您将看到:
--- 相等谓词演示 ---(eq list1 list2) -> NIL (内存中的不同对象)(equal list1 list2) -> T (结构上等价)
--- 数值谓词演示 ---(oddp 7) -> T(evenp 10) -> T(zerop 0.0) -> T(= 5 5.0) -> T (数值相等)(> 10 5 1) -> T(< 2 4 8) -> T
--- 类型谓词演示 ---(listp '(1 2 3)) -> T(atom 'my-symbol) -> T(stringp "Hello") -> T(null nil) -> T实际应用:使用 zerop 计算阶乘
Section titled “实际应用:使用 zerop 计算阶乘”谓词是控制程序流程的基础。这是一个经典的递归阶乘函数,它使用 zerop 谓词作为其基本情况。
factorial.lisp
Section titled “factorial.lisp”;;; factorial.lisp - 递归阶乘实现
(defun factorial (n) "计算非负整数 N 的阶乘。" (check-type n (integer 0 *) "N 必须是非负整数。") (if (zerop n) 1 ; 基本情况:0! = 1 (* n (factorial (1- n))))) ; 递归步骤:n * (n-1)!
;; 示例用法:(let ((num 6)) (format t "Factorial of ~d is: ~d~%" num (factorial num)))执行此代码将产生:
Factorial of 6 is: 720最佳实践与深入学习
Section titled “最佳实践与深入学习”- 选择相等比较:
eq用于符号比较,eql作为一般默认值,equal用于比较列表或序列,当需要灵活的、不区分大小写或不区分类型的比较时,使用equalp。 - 数值比较: 始终使用
=进行数字比较,而不是eql或equal,因为=能正确处理不同的数字类型(例如整数和浮点数)。 - 错误检查: 使用谓词进行健壮的错误检查。阶乘示例中的
check-type宏是强制参数具有正确类型的强大方法。