メソッドオブジェクトを関数として呼び出すにはどうすればよいですか?
Closer-mopとclosパッケージはどちらも、メソッド オブジェクトを関数に変換するためのメソッド関数を提供します。ただし、別のパッケージを含めずにそれを行う方法はありますか? そうでない場合、どのパッケージですか?(SBCLを使用)しかし、パッケージが必要な場合、識別機能はどのようにそれを行いますか?
これは、find-method を使用してメソッド オブジェクトを取得する例です。問題は、method-to-be- call を呼び出す方法です。
(defclass a () ((x :accessor x :initform 0)))
(defgeneric inc (i))
(defmethod inc ((i a)) (incf (x i)))
(defvar r (make-instance 'a))
;; ... in a land far far away:
(defvar method-to-be-called (find-method #'inc '() '(a)))
(funcall method-to-be-called r);; crashes and burns
二次的な質問として、ドキュメントによると、識別関数は最初にクラスごとに計算してメソッドオブジェクトを見つけようとし、それが失敗した場合はcompute-applicable-methodsを使用します。なぜこの 2 層アプローチを採用するのでしょうか。find-methodがこの 2 層のアプローチを行っていると仮定するのは正しいので、 find- methodを使用する方がよいでしょうか?
-- 付録 -- 以下のコメントで、Rainer Joswig は、この検索メソッドの形式は実装に依存していると指摘しました。
(find-method #'inc '() '(a))) ; works on sbcl 1.3.1
彼は、指定子リストはクラスであるべきだと言い、代わりに次のように提案します:
(find-method #'inc '() (list (find-class 'a))))
だから私は自分のクラスをそこに置くことを考えました:
(find-method #'inc '() (list a)) ; crashes and burns
どうやら(defclass a ... )はaをクラスに設定していません。実際、それは何にも設定されていません!
* (defclass a () ((x :accessor x :initform 0)))
#<STANDARD-CLASS COMMON-LISP-USER::A>
* a
... 変数 A はバインドされていません。
ただし、これは機能します。
* (defvar ca (defclass a () ((x :accessor x :initform 0))))
CA
* (defmethod inc ((i a)) (incf (x i)))
WARNING: Implicitly creating new generic function COMMON-LISP-USER::INC.
#<STANDARD-METHOD COMMON-LISP-USER::INC (A) {1005EE8263}>
enter code here
* (find-method #'inc '() (list ca))
#<STANDARD-METHOD COMMON-LISP-USER::INC (A) {1005EE8263}>
*
したがって、クラスは、defclass に提供されるシンボルの値ではなく、defclass からの戻り値です。