7

Keene の本を読むと、ジェネリック定義自体でメソッドを指定できるように見えるオプションdefgenericがあることに気付きました。:method私が見たほとんどのドキュメントには、適用可能なすべてのメソッドが個別defmethodの s で定義されています。hyperspec、通常の明確さで:method、 のオプションとしてリストされていますがdefgeneric、それが何を意味するかは述べていません。

オプションはデフォルトを提示しますか:method、または少なくとも、最も一般的なユースケースが予想されるものを文書化しますか、または追加のセマンティクスがありますか? スタイル ポイントとして、メソッドを 1 つだけ定義すると予想される場合は、それをdefgenericフォームで定義する方が理にかなっていますか (実際にそれができる場合)、または で個別に定義する方が合理的defmethodですか? それとも、この場合ジェネリック関数を作成し、代わりに通常の関数を使用するのは意味がありませんdefunか?

4

2 に答える 2

8

ハイパースペックは、通常の明確さで、defgeneric のオプションとして :method をリストしていますが、それが何を意味するかは述べていません。

実際、 defgeneric のHyperSpecエントリは、通常の明快さで、それが何を意味するかを正確に示しています。defgeneric の構文は次のとおりです。

defgeneric 関数名 gf-lambda-list [[オプション | {メソッドの説明}*]]

method-description の構文は次のとおりです。

メソッドの説明::= (:method メソッド修飾子* 特殊ラムダリスト [[宣言* | ドキュメント]] フォーム*)

そして、method-combinationについて説明します:

各メソッド記述は、ジェネリック関数のメソッドを定義します。各メソッドのラムダ リストは、gf-lambda-list オプションで指定されたラムダ リストと一致する必要があります。メソッドの説明が指定されておらず、同じ名前のジェネリック関数がまだ存在しない場合は、メソッドのないジェネリック関数が作成されます。

したがって、:method フォームは、defmethodフォームと同様に、ジェネリック関数でメソッドを定義するためのものです。

(defmethod ではなく defgeneric と :method を好む理由については、実際には何も述べていないことを認めます。Common Lisp のCommonは、言語が多くの既存の Lisp 実装を統合する試みであることを意味することを思い出してください。多分:method をサポートするものもあれば、defmethod をサポートするものもあり、これが統一されたインターフェイスを提供する最も簡単な方法でした。)

つまり、以下は同じ効果があります。

(defgeneric to-list (object))

(defmethod to-list ((object t))
  (list object))

(defmethod to-list ((object list))
  object)

(defgeneric to-list (object)
  (:method ((object t)) 
    (list object))
  (:method ((object list))
    object))

defgeneric 形式でいくつかのメソッドを定義すると便利な場合があります。それはスタイルの問題であり、これは質問の他の部分に入ります。

:method オプションは、デフォルト、または少なくとも、最も一般的なユースケースが予想されるドキュメントを提示しますか?それとも追加のセマンティクスがありますか?

型指定子なしでメソッドを定義する場合、またはすべてのオブジェクトに適用される型指定子 (たとえばt ) を使用してメソッドを定義する場合、これは一種のデフォルトになる可能性があります。

スタイル ポイントとして、メソッドを 1 つだけ定義すると予想される場合、それを defgeneric 形式で定義すること (実際にそれができる場合) と、defmethod で個別に定義することのどちらがより理にかなっていますか? それとも、この場合ジェネリック関数を作成し、代わりに通常の defun を使用するのは意味がありませんか?

メソッドを1つだけ定義する理由に依存すると思います。デフォルトを定義しているだけで、他のユーザーがそれにメソッドを実装することを期待している場合、ソースを見つける必要がある場合は、メソッドを defmethod と一緒に配置すると便利な場合があります。やるべきことが 1 つだけだと予想される場合は、通常の関数の方が理にかなっている可能性があります。これらの決定は、スタイルの選択に帰着すると思います。

ジェネリック関数でメソッドを定義できる他のフォーム (およびジェネリック関数を生成できる他のフォーム) があることも注目に値します。HyperSpec では、上矢印を使用してより高いセクションに移動すると、通常、より多くの散文が表示されます。この場合、7.6.1 ジェネリック関数の紹介が役に立ちます。

一部の演算子は、ジェネリック関数のメソッドを定義します。これらの演算子は、メソッド定義演算子と呼ばれます。それらに関連付けられたフォームは、メソッド定義フォームと呼ばれます。標準化されたメソッド定義演算子を次の図に示します。

defgeneric        defmethod  defclass  
define-condition  defstruct
于 2015-04-15T02:59:17.110 に答える
2

それは個人の好みと、システムがソースでどのように編成されるか次第です。また

  • 単純なジェネリック関数: たくさんDEFMETHODS

  • 複雑なジェネリック関数: aDEFGENERICおよび一連のDEFMETHODS

  • ジェネリック関数:DEFGENERICおよび内部のメソッドの束

CLOS より前のほとんどの Lisp オブジェクト指向システムは、単一メソッド定義形式を使用していました。そうしないと、コードが 1 つの形式で長くなりすぎる可能性があり、一般的な関数はほとんど存在しませんでした...

クラス指向の単一ディスパッチ システムでは、クラス定義でメソッドを編成することが理にかなっている可能性があります。ジェネリック関数と複数のディスパッチの導入により、それらをジェネリック関数定義の下で整理することが理にかなっています。

于 2015-04-15T13:48:28.527 に答える