2014-02-20 33 views
3

我正在嘗試在Common Lisp中執行多方法的「重載調用」。這裏是這樣的簡化概要:「重載」使用不同參數列表的CLOS多方法

(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的一部分,所以我覺得我可能會吠叫錯誤的樹。

+1

這不是超載。重載意味着提前(編譯時)綁定同名的符號。 CLOS所做的是_dispatch_,即遲到(運行時)綁定。如果您有不同數量的參數,則不需要將其推遲到運行時間。約束條件就是您不能擁有多個具有相同完全限定名稱的泛型函數。 – Svante

回答

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

3

通用函數的所有方法都必須有一致的參數列表。如果您具有相同數量的必需參數,相同數量的可選參數,並且以兼容的方式使用&rest&key,則參數列表是一致的。

但是,當然,您不能專注於&optional,&rest&key參數的類型。