6

Common lispの場合:スコープ内の既存の関数を再定義しますか?OPは似たようなものを求めました。しかし、関数ではなく、メソッドスペシャライザーを作成したいと思います。基本的に、メソッドが次のように定義されていると仮定します。

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(目的は、古いスロット値と新しいスロット値をどこかに記録してから、次のメソッドを呼び出すことです。)すでにインスタンス化された標準オブジェクトをインターセプトしたい場合があるため、メタクラスを作成したくありません。

もちろん試してみましたが、うまくいきませんでしたが(どうやってDEFMETHODLABELS)、経験豊富な人にそのような方法で実行できないことを確認したり、適切な方法を提案したりしたいと思いました。

コメント?

編集:

DanielとTerjeは、可能性に向けて私の知識を広げるための優れたリンクを提供しますが、そこに行く前に、よりバニラなアプローチを探すためにもう少しプッシュしたいと思います。私は、環境に入るときにadd-methodを実行することを検討してきました。これは、eqlに特化し、終了時にremove-methodを実行します。私はまだ終わっていません。誰かがそれらで遊んだことがあるなら、コメントはいいでしょう。スレッドを最新の状態に保ちます。

編集2:私はadd-methodシナリオでそれを行うのに近いですが、問題があります。これが私が試したことです:

    (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)
       )))      

オブジェクトスロットとデータを引数として(my-test)を呼び出すと、次のようになります。

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メソッドが含まれるようになったため、特殊化は機能しますが、残念ながら呼び出されないようです。誰かが助けてくれるので、私はそれを終えて、それを甘い小さなユーティリティマクロにリファクタリングすることができますか?

4

2 に答える 2

5

いいえ、CommonLispで動的エクステントまたは字句スコープの特殊なメソッドを定義することはできません。

アスペクト指向プログラミングは、根本的な問題を解決するためのアプローチとして使用できます。コンテキスト指向プログラミングも参照してください。

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...))

ただし、ロギングが無効になっている場合にも:aroundメソッドが呼び出されることに注意してください。

于 2011-04-27T15:27:54.860 に答える
3

generic-fletCommon Lispにはかつてgeneric-labels特別なフォームが提案されていたようですが、実装によってサポートされることはめったになく、設計が不十分であると見なされたため、最終仕様から削除されました。HyperSpecの問題GENERIC-FLET-POORLY-DESIGNED書き込みを参照してください。字句スコープの関数よりも字句メソッドの方が役に立たないと人々が考えた理由についての議論を読むのは興味深いことです。

したがって、それらがなければ、字句スコープのメソッドを作成する方法はないと思いますが、Terjeが別の回答でリンクしたContextLで遊んだことはないので、必要なものが提供される可能性があります。

于 2011-04-27T15:39:39.597 に答える