如何在 common-lisp CLOS 中指向一个 defgeneric 实例
Posted
技术标签:
【中文标题】如何在 common-lisp CLOS 中指向一个 defgeneric 实例【英文标题】:How to point to a defgeneric instance in common-lisp CLOS 【发布时间】:2020-01-25 09:46:28 【问题描述】:这里是lisp初学者。
我知道如何使用函数 find-method 指向特定的方法实例,我从使用 slime 检查返回的方法实例中看到它有一个插槽 %GENERIC-FUNCTION,但我不能使用它。
(为什么(slot-value (find-method ...) '%GENERIC-FUNCTION)
告诉我对象中缺少插槽。
那么,我应该如何从 defmethod 对象指向一个 defgeneric 呢? 我正在使用 sbcl,但是否有标准化的 common-lisp 方式来实现兼容性?
【问题讨论】:
【参考方案1】:%GENERIC-FUNCTION
可能是指当前包中的符号,而不是内部包中标识插槽的符号。它们具有相同的名称,但属于不同的包。
您所做的与 CLOS 的元对象协议 (MOP) 有关,请参阅metamodular.com/CLOS-MOP 了解更多信息(另请阅读AMOP)。
我们先加载closer-mop
:
USER> (ql:quickload :closer-mop)
To load "closer-mop":
Load 1 ASDF system:
closer-mop
; Loading "closer-mop"
(:CLOSER-MOP)
Closer-MOP 系统是:
[...] 一个兼容层,可以纠正许多缺失或 广泛的 Common Lisp 中不正确的 CLOS MOP 功能 实现。
USER> (find-method #'print-object () (mapcar #'find-class '(vector t)))
#<STANDARD-METHOD COMMON-LISP:PRINT-OBJECT (VECTOR T) 10005605C3>
(感谢 RainerJoswig 指出专门器列表应该包含类对象而不是符号)
USER> (closer-mop:class-direct-slots (class-of *))
(#<SB-MOP:STANDARD-DIRECT-SLOT-DEFINITION SB-PCL::%GENERIC-FUNCTION>
#<SB-MOP:STANDARD-DIRECT-SLOT-DEFINITION SB-PCL::QUALIFIERS>
#<SB-MOP:STANDARD-DIRECT-SLOT-DEFINITION SB-PCL::SPECIALIZERS>
#<SB-MOP:STANDARD-DIRECT-SLOT-DEFINITION SB-PCL::LAMBDA-LIST>
#<SB-MOP:STANDARD-DIRECT-SLOT-DEFINITION SB-PCL::%FUNCTION>
#<SB-MOP:STANDARD-DIRECT-SLOT-DEFINITION SB-PCL::%DOCUMENTATION>
#<SB-MOP:STANDARD-DIRECT-SLOT-DEFINITION SB-PCL::SIMPLE-NEXT-METHOD-CALL>)
确实,您需要使用SB-PCL::%GENERIC-FUNCTION
符号:
USER> (slot-value ** 'SB-PCL::%GENERIC-FUNCTION)
#<STANDARD-GENERIC-FUNCTION COMMON-LISP:PRINT-OBJECT (277)>
(回想一下 *
和 **
是表示 REPL 中计算的最后一个和倒数第二个值的变量)
备注
此插槽的SB-PCL::%GENERIC-FUNCTION
符号未导出(我们需要两个冒号来引用它),它以%
字符开头,这是internal 的约定(有时危险)符号。你不应该直接使用它;也不推荐直接调用slot-value
,一般只需要accessor函数即可。
method-generic-function
相反,您应该使用从closer-mop
导出的符号以获得更好的兼容性:
(closer-mop:method-generic-function
(find-method #'print-object () (mapcar #'find-class '(vector t))))
【讨论】:
(find-method #'print-object () (list 'vector t))
不可移植。您需要传递一个类对象列表。请参阅 CLHS 7.6.2:参数专用器名称用于宏中,用作用户级接口(defmethod),而参数专用器用于功能接口。以上是关于如何在 common-lisp CLOS 中指向一个 defgeneric 实例的主要内容,如果未能解决你的问题,请参考以下文章