在Common Lisp中能否自定义可迭代类以适配SEQUENCE相关操作?
在Common Lisp中为自定义类实现序列兼容性
完全可行,而且这是Common Lisp里扩展标准行为的常规操作——因为Common Lisp的序列系统基于广义序列(Generalized Sequence)设计,并非仅绑定到内置的list、vector等类型,只要自定义类实现了序列协议的必要方法,就能让所有标准序列函数/宏直接作用于其实例。
需要实现的核心方法
要让自定义类支持你提到的loop迭代、sort、aref等操作,需实现以下关键方法(以一个内部用向量存储元素的自定义容器类为例):
- 定义继承自
sequence的类sequence是Common Lisp的标准抽象类,继承它能明确告诉系统这个类属于序列范畴:
(defclass my-container (sequence) ((elements :initarg :elements :accessor elements :type vector)))
- 实现
length方法
返回实例包含的元素总数:
(defmethod length ((obj my-container)) (length (elements obj)))
- 实现
elt方法
支持通过索引获取元素(aref会自动调用该方法处理序列类型):
(defmethod elt ((obj my-container) index) (elt (elements obj) index))
- 可选:支持元素修改
如果需要修改元素,实现(setf elt)方法:
(defmethod (setf elt) (new-value (obj my-container) index) (setf (elt (elements obj) index) new-value))
- 可选:支持
sort返回同类型实例
要让sort返回自定义类的实例而非内置序列,需实现make-sequence方法:
(defmethod make-sequence ((class (eql 'my-container)) length &key initial-element) (make-instance 'my-container :elements (make-array length :initial-element initial-element)))
验证使用
完成上述实现后,你就可以像使用内置序列一样操作自定义类实例:
;; 创建实例 (defvar *my-instance* (make-instance 'my-container :elements #(3 1 4 2))) ;; 使用loop迭代 (loop for x across *my-instance* do (print x)) ;; 输出:3、1、4、2 ;; 使用sort排序 (sort *my-instance* #'<) ;; 返回一个my-container实例,内部元素为#(1 2 3 4) ;; 使用aref获取索引元素 (aref *my-instance* 3) ;; 输出:2
注:loop for x in ...是专门针对链表的语法,对于自定义序列类,更通用的是用across;如果一定要支持in,可以额外实现链表转换的方法(比如list方法),但通常across是序列的标准迭代方式。
内容的提问来源于stack exchange,提问作者Duncan Britt
相关产品推荐
相关产品推荐

