5

我遇到了一个问题,第三方库需要对一个类进行操作,就好像它已经完成一样。经过一番阅读,我了解了这种机制背后的动机,但我真的不知道它是如何运作的。

例子:

(make-instance 'expression :op '+ :left 'nan :right 'nan)
(defmethod normalize-expression ((this expression))
  (optima:match this
    ((optima::or (expression :left 'nan) (expression :right 'nan)) 'nan)
    ((expression :op op :left x :right y) (funcall op x y))))

除非我添加第一行,否则该函数将无法编译,给我这个错误:

; caught ERROR:
;   (during macroexpansion of (SB-PCL::%DEFMETHOD-EXPANDER NORMALIZE-EXPRESSION ...))
;   SB-MOP:CLASS-SLOTS called on #<STANDARD-CLASS EXPRESSION>, which is not yet finalized.
;   See also:
;     AMOP, Generic Function SB-MOP:CLASS-SLOTS

optima是一个模式匹配库,(expression :op op ...)它将类的实例expression与给定的模式匹配。我不知道很多细节,但看起来它需要知道为这个类定义的访问器是什么,而且看起来这些信息在最终确定之前是不可用的。那么,有没有办法回避最终确定的问题呢?

该课程不会被扩展(至少不会在这个项目中,也没有计划)。创建一个虚拟实例并没有那么大的伤害......这只是一个丑陋的解决方案,所以我希望找到一个更好的解决方案。另外,也许,我会得到更多关于定稿的信息,这也很好:)

4

1 回答 1

9

在使用 MOP 时,忘记确保类终结似乎是很常见的错误。

在 lisp 中,类在两个“阶段”中定义:

  • 直接类定义
  • 有效的类定义

直接类定义与形式同构defclass。它有类名、超类名、直接槽列表(即,在这个特定类上但在其超类上定义的槽)。

有效的类定义包含编译器/解释器所需的所有信息。它包含所有类插槽的列表(包括在超类上定义的插槽)、类实例布局、对访问器方法的引用等。

将直接类定义转换为有效类定义的过程称为类终结。由于 CLOS 支持重新定义类,因此可能会为一个类多次调用 finalization。最终确定延迟的原因之一是因为类可能在定义其超类之前定义。

关于您的特定问题:似乎optima:match应该确保在尝试列出其插槽之前完成该类。这可以通过两个函数来完成:(class-finalized-p检查类是否需要终结)和finalize-inheritance实际执行终结。或者你可以使用实用功能closer-mop:ensure-finalized。(closer-mop 是一个可移植使用 CLOS MOP 的库)。

例如,:

(c2mop:ensure-finalized (find-class 'expression))
于 2013-07-30T04:13:26.083 回答