Common Lisp类型说明符中vector元素类型校验意外行为疑问
核心原因
Common Lisp的数组(包含vector)类型说明符中的元素类型参数,不会在typep检查时遍历验证所有元素符合该类型,它仅用于匹配数组的「升级后实际存储元素类型」是否兼容你指定的元素类型。
CL规范允许实现对数组元素类型做「类型升级」:实现会自动选择一种可以容纳所有指定类型元素的实际存储类型,该行为是实现相关的。对于(satisfies oddp)这类自定义派生类型,几乎所有Common Lisp实现都无法为其设计专门的存储格式,会直接将其升级为最通用的t类型,因此(vector (satisfies oddp))本质上等价于(vector t),会匹配所有普通vector,自然三个检查全部返回t。
typep对vector类型的检查逻辑为:判断vector实际的升级后元素类型,是否是你指定的元素类型的子类型。因为t是所有类型的超类型,任何指定的元素类型都是t的子类型,所以所有元素类型为t的普通vector,都能匹配任意(vector 任意类型)的检查,这就是你遇到的问题的根源。
简化的校验方案
你无需每次都手动写全检查逻辑,可以封装通用工具来减少模板代码:
;; 通用vector内容检查构造函数 (defun make-vector-predicate (element-pred) (lambda (v) (and (vectorp v) (every element-pred v)))) ;; 定义奇数整数vector的检查函数 (defparameter *odd-int-vector-p* (make-vector-predicate (lambda (n) (and (integerp n) (oddp n))))) ;; 调用示例 (let ((v1 (vector 1 3)) (v2 (vector 1 3 4)) (v3 (vector 1 3 "4"))) (values (typep v1 `(satisfies ,*odd-int-vector-p*)) (typep v2 `(satisfies ,*odd-int-vector-p*)) (typep v3 `(satisfies ,*odd-int-vector-p*))))
如果使用频率更高,你还可以定义宏来直接生成对应的类型说明符,进一步简化写法。
内容的提问来源于stack exchange,提问作者lupl
相关产品推荐
相关产品推荐

