CLOSディスパッチのみを使用して、この正確なタスクを簡単に実行することはできません。
先に進む前に、用語について簡単に説明しておくことが重要だと思います。
Common Lisp HyperSpec 用語集では、 「サブクラス」を次のように定義しています。
スーパークラスと呼ばれる、別のクラスから継承するクラス。(どのクラスもそれ自体のサブクラスではありません。)
この定義は直感的ですが、「適切なサブクラス」の定義であると予想されるため、私には奇妙に思えます。ただし、すべてのクラスは型であり、「サブタイプ」を次のように定義します。
メンバーシップが、スーパータイプと呼ばれる別のタイプのメンバーシップと同じか、そのメンバーシップの適切なサブセットであるタイプ。(すべてのタイプはそれ自体のサブタイプです。)
「すべてのタイプはそれ自体のサブタイプです」という括弧に注意してください。
また、「適切なサブタイプ」も定義します。
(型の) 型と同じ型ではない型のサブタイプ (つまり、その要素は型の「適切なサブセット」です)。
したがって、あなたの例では、 B と C は A のサブクラスであり、サブタイプでもあります。一方、B、C、および Aは A のサブタイプです。
defmethod に入れるのは「パラメータ特化名」です。シンボル、クラス (入力が少し難しい)、または eql で始まるリストを指定できます。シンボルを指定すると、そのシンボル (もちろん、型) によって名前が付けられたクラスが指定されます。eql リストは、リスト内のものと等しいオブジェクトで構成される型を指定します。
このメソッドは、スペシャライザーが指定する型のメンバーであるすべてのオブジェクトに一致します。もちろん、X のサブタイプのメンバーは X のメンバーでもあります。
したがって、最初の問題は、シンボル オブジェクトをメソッドに渡すことです。すべてのシンボルはタイプSYMBOL
です。この点では、たまたまクラスに名前を付けるシンボルも同じです。クラスとの唯一の関係は、それがクラスの名前であり、サブタイプの関係ではないということです。
クラス オブジェクト ( によって返されるfind-class
) がありますが、クラス オブジェクトの型は通常、そのサブクラスのクラス オブジェクトの型と同じであるため、ここではメソッドの特殊化のシンボルにすぎません。
そのため、インスタンスを使用したり、AMOPを読んだりして、独自の型のジェネリック関数を作成する方法を学ぶ必要があります。
インスタンスを作成したら、次のようにメソッドを記述できます。
(defmethod fun ((param a))
(if (eq (type-of param) 'a)
(call-next-method)
(format t "~a is a subclass of A~%" (type-of param))))
クラスのインスタンスを取得する簡単な方法がある場合は、次のラッパーを記述できます。
(defmethod fun ((param symbol))
(fun (retrieve-instance param)))
次に、シンボルを fun に渡して、必要な結果を得ることができます。
AMOP 関数 (標準では指定されていませんが、広く利用可能です。Closer Projectretrieve-instance
を参照してください) を使用する場合は、次のように定義できます。
(defun retrieve-instance (name)
(let ((class (find-class name)))
(unless (class-finalized-p class)
(finalize-inheritance class))
(class-prototype class)))
メソッドのディスパッチは、 の結果が役立つ唯一のものであることに注意してくださいclass-prototype
。それを変更しようとしないでください。