我正在尝试在Common Lisp中执行多方法的“重载调用”。这是案例的简化纲要:
(defclass foo ()
((slotty :accessor slotty :initarg :slotty)))
(defclass bar ()
((slotty :accessor slotty :initarg :slotty)))
(defparameter *foo* (make-instance 'foo :slotty "defnoodle"))
(defparameter *bar* (make-instance 'bar :slotty "Chocolate"))
(defmethod contrived ((f foo) (b bar))
(format t "i pity the foo ~A, who has a bar ~A ~%" (slotty f) (slotty b)))
(contrived *foo* *bar*)
输出:i pity the foo defnoodle, who has a bar Chocolate
但是一旦我尝试定义下一个方法:
(defmethod contrived ((f foo))
(format t "i just pity the foo ~A ~%" (slotty f)))
CL生气了:
; The generic function #<STANDARD-GENERIC-FUNCTION CONTRIVED (1)>
; takes 2 required arguments; was asked to find a method with
; specializers (#<STANDARD-CLASS FOO>)
; [Condition of type SB-PCL::FIND-METHOD-LENGTH-MISMATCH]
; See also:
; Common Lisp Hyperspec, FIND-METHOD [:function]
有谁知道我在做错了什么?我知道initialize-instance具有类似的灵活性,因为每个类应该能够为每个类和每个任意数量的参数识别n个初始化实例方法。
(defmethod initialize-instance :after ((f foo) &key)
())
但我不清楚如何将其转化为我上面给出的香草例子。而且我觉得我可能会咆哮错误的树,因为这是MOP的一部分。
答案 0 :(得分:6)
你写道:有谁知道我在做错了什么?
说清楚:CLOS不支持。在单个泛型函数的方法的方法参数列表中,不能有不同数量的必需参数。调度仅适用于所需的参数。 Common Lisp不支持'重载'。
INITIALIZE-INSTANCE
使用以下语法定义:
initialize-instance instance &rest initargs &key &allow-other-keys => instance
所有方法都需要一个必需的参数,即实例。仅对此对象执行调度。然后它允许各种关键字参数 - 不为它们进行调度。
所以你需要就你的泛型函数应该采用的所需参数的数量达成一致,并在你的代码中以这种方式调用它。
请参阅CL Hyperspec了解规则:Congruent Lambda-lists for all Methods of a Generic Function。
答案 1 :(得分:3)
泛型函数的所有方法都必须具有一致的参数列表。如果您具有相同数量的必需参数,相同数量的可选参数,并且以兼容方式使用&rest
和&key
,则参数列表是一致的。
但是,当然,您无法专注于&optional
,&rest
或&key
参数的类型。