您将无法仅使用 CLOS 调度轻松地执行这个确切的任务。
在我继续之前,我认为一些关于术语的简短说明很重要。
Common Lisp HyperSpec 词汇表以这种方式定义“子类”:
从另一个类继承的类,称为超类。(没有类是它自己的子类。)
这个定义虽然直观,但对我来说似乎很奇怪,因为我希望这是“适当的子类”的定义。但是,所有类都是类型,它将“子类型”定义为:
一种类型,其成员资格与另一种类型的成员资格相同或它的适当子集,称为超类型。(每种类型都是其自身的子类型。)
请注意括号中的内容:“每种类型都是其自身的子类型。”
它还定义了一个“正确的子类型”:
(of a type) 类型的子类型,与类型不同的类型(即,它的元素是类型的“正确子集”)。
因此,在您的示例中,B 和 C 是 A 的子类,也是子类型。另一方面,B、C和 A是 A 的子类型。
放在 defmethod 中的东西是“参数专业名称”。它可以是一个符号、一个类(有点难打)或一个以 eql 开头的列表。如果您提供一个符号,它指定由该符号命名的类(当然,它是一种类型)。一个 eql 列表指定一个类型,该类型由与列表中的事物 eql 的对象组成。
该方法将匹配作为专门器指定类型的成员的任何对象。当然,X 子类型的成员也是 X 的成员。
所以你的第一个问题是你将符号对象传递给你的方法;每个符号都是 type SYMBOL
。碰巧命名一个类的符号在这方面没有什么不同。它与类的唯一关系是它是类的名称,而不是子类型关系。
有类对象(由 返回find-class
),但在这里它们并不比方法特化的符号更好,因为类对象的类型通常与其子类的类对象的类型相同。
因此,您只能使用实例或阅读AMOP来学习如何创建自己的泛型函数类型。
一旦你有了一个实例,你可以像这样编写方法:
(defmethod fun ((param a))
(if (eq (type-of param) 'a)
(call-next-method)
(format t "~a is a subclass of A~%" (type-of param))))
如果你有一种简单的方法来检索你的类的实例,你可以编写这个包装器:
(defmethod fun ((param symbol))
(fun (retrieve-instance param)))
然后,您将能够将符号传递给乐趣并获得您想要的结果。
如果您想使用 AMOP 函数(标准未指定但广泛使用,请参阅Closer Project),您可以retrieve-instance
这样定义:
(defun retrieve-instance (name)
(let ((class (find-class name)))
(unless (class-finalized-p class)
(finalize-inheritance class))
(class-prototype class)))
请注意,方法分派几乎是唯一有利于结果的事情class-prototype
;不要试图修改它或类似的东西。