2011-04-27 62 views
6

Common lisp: Redefine an existing function within a scope? OP要求類似的東西。但是我想創建一個方法專家,而不是一個功能。 本質假設的方法是這樣定義:lisp:如何在範圍內創建臨時方法專業

defmethod my-meth ((objA classA) (objB classB)) (...) 

我想什麼做的是(僞):

(labels ((my-meth ((objA classA) (objB (eql some-object))))) 
    do stuff calling my-meth with the object...) 

真正的用途是,我想創建一個臨時的環境下,setf slot-value-using-class將專門針對eql,重點創建一個特定對象的按需截取其插槽寫作。 (目的是記錄舊的和新的插槽值,然後調用下一個方法。)我不想創建元類,因爲我可能想攔截已經實例化的標準對象。

當然,我嘗試了它並沒有奏效(因爲DEFMETHOD如何在LABELS?),但我希望一些更有經驗的人來驗證它是不可行和/或提出合適的辦法。

評論?

編輯:

丹尼爾和泰耶提供優異的鏈接,擴大我對準備知識,但我想以前去那裏多一點推動它在尋找一個更香草的方法。我一直在考慮在進入環境時進行add-method,這將專注於eql,並在退出時執行remove-method。我還沒有完成。如果有人玩過這些,評論會很好。將保持線程是最新的。

編輯2:我接近做與添加方法的場景,但有一個問題。這是我曾嘗試:

(defun inject-slot-write-interceptor (object fun) 
    (let* ((gf (fdefinition '(setf sb-mop:slot-value-using-class))) 
      (mc (sb-mop:generic-function-method-class gf)) 
      (mc-instance (make-instance (class-name mc) 
          :qualifiers '(:after) 
          :specializers (list (find-class 't) 
               (find-class 'SB-PCL::STD-CLASS) 
               (sb-mop::intern-eql-specializer object) 
               (find-class 'SB-MOP:STANDARD-EFFECTIVE-SLOT-DEFINITION)) 
          :lambda-list '(new-value class object slot) 
          :function (compile nil (lambda (new-value class object slot) (funcall fun new-value class object slot)))))) 
     (add-method gf mc-instance) 
     (defun remove-slot-write-interceptor() 
      (remove-method gf mc-instance)) 
     )) 

(defun my-test (object slot-name data) 
    (let ((test-data "No results yet") 
      (gf (fdefinition '(setf sb-mop::slot-value-using-class)))) 
     (labels ((show-applicable-methods() (format t "~%Applicable methods: ~a" (length (sb-mop:compute-applicable-methods gf (list data (class-of object) object (slot-def-from-name (class-of object) slot-name))))))) 
      (format t "~%Starting test: ~a" test-data) 
      (show-applicable-methods) 
      (format t "~%Injecting interceptor.") 
      (inject-slot-write-interceptor object (compile nil (lambda (a b c d) (setf test-data "SUCCESS !!!!!!!")))) 
      (show-applicable-methods) 
      (format t "~%About to write slot.") 
      (setf (slot-value object slot-name) data) 
      (format t "~%Wrote slot: ~a" test-data) 
      (remove-slot-write-interceptor) 
      (format t "~%Removed interceptor.") 
      (show-applicable-methods) 
     )))  
一些對象插槽和數據

調用(我的測試)爲ARGS結果:

Starting test: No results yet 
Applicable methods: 1 
Injecting interceptor. 
Applicable methods: 2 
About to write slot.  
Wrote slot: No results yet <----- Expecting SUCCESS here.... 
Removed interceptor. 
Applicable methods: 1 

所以我在這裏停留。因爲適用的方法現在包含eql-specialized:after方法,所以專門化可以工作,但不幸的是它似乎沒有被調用。任何人都可以幫助我完成它並將它重構爲一個可愛的小公用程序宏?

+0

方法定義是全局的,因此在詞彙或動態環境中添加和刪除方法將影響其他線程(假設多處理)。 – 2011-04-27 16:58:24

+0

hmm,shit ......除非......在我的使用案例中,我想專門研究一個特定的實例,因此如果實例被共享,那麼所有線程都將受到影響,這是我想要的,如果不共享,動態方法將不適用。雖然我希望像一個更抽象的「工具般」的包裝...感謝您的鐘聲。 – Paralife 2011-04-27 17:20:01

+1

要全局啓用特定實例的日誌記錄,請考慮使用'change-class'將實例的類更改爲具有執行日誌記錄的'my-meth:around'方法的子類,然後通過更改回原始來禁用日誌記錄類。使用宏來編寫抽象包裝。 – 2011-04-27 17:41:05

回答

5

不,您不能在Common Lisp中定義動態範圍或詞彙範圍的專用方法。

Aspect Oriented Programming可用作解決潛在問題的方法。另見Context-Oriented Programming

ContextL是一個爲Common Lisp/CLOS提供面向方面擴展的庫。

的輕重量的替代方法是使用一個特殊的/動態變量來指示該方法應該做的記錄:

(defparameter *logging* NIL "Bind to a true value to activate logging") 

(defmethod my-meth :around ((objA classA) (objB (eql some-object))) 
    (prog2 
    (when *logging* 
    (logging "Enter my-meth")) 
    (call-next-method) 
    (when *logging* 
    (logging "Exit my-meth")))) 

(let ((*logging* T)) 
    (do stuff calling my-meth with the object...)) 

不過要注意的是:各地的方法將被調用時也禁用日誌記錄。

+0

也許這是我要做的,如果添加/刪除方法不起作用,但我希望有一個完全動態的方式... – Paralife 2011-04-27 16:12:31

+0

考慮使用宏的語法糖,它允許您按照您的方式編寫「方法重定義」喜歡做,即使底層的實現是一個較小的黑客。 – 2011-04-27 17:04:21

3

看來有一次爲generic-fletgeneric-labels提出了Common Lisp的特殊形式,但它從最終規範中被刪除,因爲它被認爲很少被實現支持並且設計不佳。請參閱HyperSpec中的Issue GENERIC-FLET-POORLY-DESIGNED Writeup。閱讀討論爲什麼人們認爲詞法方法比詞法範圍函數沒那麼有用是很有趣的。因此,如果沒有這些,我真的不認爲有一種方法可以創建詞法範圍方法,儘管我還沒有玩過Terje鏈接到另一個答案的ContextL,所以它可能會提供您所需要的。

+0

原因真的不存在,對我來說至少。一次,綁定將泛型函數本地化的有用性和將類定義本地化的(實現這種想法)的用處對我來說是沒有意義的。看起來他們只是想要一個不存在的執行標準。對我來說,這是刪除它們的唯一合理理由。但是,我仍然需要這個,或者更真誠地說,我會喜歡它:)我認爲我的用例是一個很好的例子。 – Paralife 2011-04-27 16:09:18