您将无法仅使用 CLOS 调度轻松地执行这个确切的任务。
在我继续之前,我认为一些关于术语的简短说明很重要。
Common Lisp HyperSpec 词汇表defines“子类”这样写:
从另一个类继承的类,称为超类。 (不
class 是它自己的子类。)
这个定义虽然直观,但对我来说似乎很奇怪,因为我希望这是“适当的子类”的定义。但是,所有的类都是类型,它defines"subtype" 为:
一种类型,其成员资格与另一种类型的成员资格相同或它的适当子集,称为超类型。 (每种类型都是其自身的子类型。)
注意括号:“每个类型都是它自己的子类型。”
它也是 defines 一个“适当的子类型”:
(属于一个类型)该类型的子类型,与该类型不同类型(即,它的元素是该类型的“正确子集”)。
因此,在您的示例中,B 和 C 是 A 的子类,也是子类型。另一方面,B、C、 和 A 是 A 的子类型。
放入 defmethod 的东西是"parameter specializer name"。它可以是一个符号、一个类(有点难打)或一个以 eql 开头的列表。如果您提供一个符号,它指定由该符号命名的类(当然,它是一种类型)。一个 eql 列表指定了一个由与列表中的事物 eql 的对象组成的类型。
该方法将匹配作为专门器指定类型成员的任何对象。当然,X 子类型的成员也是 X 的成员。
所以你的第一个问题是你将符号对象传递给你的方法;每个符号都是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 结果的唯一好处;不要试图修改它或类似的东西。