如何用Common Lisp的deftype定义成员均为指定类型的列表类型?
Common Lisp 自定义
list-of类型的正确实现 你的问题核心是:deftype必须返回合法的类型说明符,而你试图在返回值中嵌入labels局部函数定义——这不符合CL类型系统的规则,因为satisfies子句要求的是全局可见的函数符号,局部函数无法被类型检查器识别。
错误原因拆解
你写的代码里,(labels (...) ...)是执行期的函数定义表达式,但CL的类型说明符只能是特定的语法结构(比如list、(and ...)、(satisfies symbol)等),不能包含执行期代码,所以系统会把labels当作无效的类型说明符成分报错。
正确实现方式
方式一:为每个类型参数生成全局检查函数
通过动态生成唯一的全局函数,让satisfies可以引用它:
(deftype list-of (type) (let ((checker-symbol (intern (format nil "LIST-OF-~A-CHECKER" type)))) ; 动态定义全局检查函数 (eval `(defun ,checker-symbol (obj) (and (listp obj) (every (lambda (item) (typep item ',type)) obj)))) ; 返回合法的类型说明符 `(satisfies ,checker-symbol)))
调用示例:
(typep '(1 3 3) '(list-of int)) ; => T (typep '(1 "string" 3) '(list-of int)) ; => NIL
注意:这种方式会在全局符号表中生成对应函数,若频繁使用不同类型参数,可能造成符号表污染,适合类型参数有限的场景。
方式二:基于全局哈希表的闭包调度(更优雅,避免符号污染)
维护一个全局哈希表存储类型到检查函数的映射,用统一的全局函数做调度:
; 全局注册表:存储类型到检查函数的映射 (defvar *list-of-checkers* (make-hash-table :test 'equal)) ; 通用检查逻辑 (defun check-list-of-type (obj type) (and (listp obj) (every (lambda (item) (typep item type)) obj))) ; 供satisfies调用的全局包装函数 (defun list-of-wrapper (obj) ; 解析当前要检查的类型参数(从类型说明符中提取) (let* ((type-spec (type-of obj)) (target-type (second type-spec))) (when-let ((checker (gethash target-type *list-of-checkers*))) (funcall checker obj)))) (deftype list-of (type) (let ((checker (lambda (obj) (check-list-of-type obj type)))) ; 将当前类型对应的检查函数存入注册表 (setf (gethash type *list-of-checkers*) checker) ; 返回合法的类型说明符 `(and list (satisfies list-of-wrapper))))
这个方式不会生成大量全局函数,适合频繁使用不同类型参数的场景。
方式三:使用第三方工具库(最省心)
如果你的项目允许依赖第三方库,可以直接用Alexandria工具库中封装好的proper-list-of类型:
; 先加载Alexandria (ql:quickload :alexandria) ; 使用示例 (typep '(1 3 3) 'alexandria:proper-list-of-int)
内容的提问来源于stack exchange,提问作者Samantha Atkins
相关产品推荐
相关产品推荐

