npt-japanese

% Macro DEFINE-METHOD-COMBINATION

UP


Macro DEFINE-METHOD-COMBINATION

Macro DEFINE-METHOD-COMBINATION

構文

define-method-combination name [[short-form-option]]
=> name

define-method-combination name lambda-list (method-group-specifier*) [(:arguments . args-lambda-list)] [(:generic-function generic-function-symbol)] [[declaration* | documentation]] form*
=> name

short-form-option::= :documentation documentation |  
                     :identity-with-one-argument identity-with-one-argument |
                     :operator operator
method-group-specifier::= (name {qualifier-pattern+ | predicate} [[long-form-option]])
long-form-option::= :description description |
                    :order order |
                    :required required-p

引数と戻り値

args-lambda-list - define-method-combination引数のラムダリスト
declaration - 宣言の式、評価はされません
description - format-control
documentation - 文字列、評価はされません form - 暗黙のprogn。 有効なメソッドをどのようにして結合させるかを計算し、 フォームとして返却しなければなりません。
generic-function-symbol - シンボル
identity-with-one-argument - generalized-boolean
lambda-list - 通常のラムダリスト
name - シンボル。 通常、キーワードではなく、nilでもないシンボルが使われます。
operator - オペレーター。 nameoperatorは、よく同じシンボルが使われます。 これがデフォルトですが、必須ではありません。
order - :most-specific-first:most-specific-last。評価されます。
predicate - シンボルであり、 それはひとつの引数を取りgeneralized-booleanを返却する関数名。
qualifier-pattern - リストか、シンボル*
required-p - generalized-boolean

定義

マクロdefine-method-combinationは、 新しいmethod-combinationの型を定義するときに使います。

define-method-combinationには2つのフォームがあります。 短いフォームは単純な機能であり、 もっとも一般的に必要があると予想されるケースに対応しています。 長いフォームはより強力で、より冗長です。 これは、defmacroのように、 通常はボディ部がバッククォートを使った式であり、 フォームを計算します。 したがって、任意の制御構造を実装することができます。 長いフォームは、メソッド修飾子を任意に処理することもできます。

もしdefine-method-combinationフォームがトップレベルフォームに現れたとき、 コンパイラーはmethod-combinationの名前が、 続くdefgenericフォームのmethod-combination名で 有効であると認識させなければなりません。 しかし、method-combinationが実行されるのは、 define-method-combinationフォームの実行時より早くはないので、 ジェネリック関数がmethod-combinationを使うときまで 可能な限り遅らせて実行されます。

例文

define-method-combinationの長いフォームの例のほとんどは、 メソッド結合の機能の宣言の一部として、 提供されている関係関数の使用も説明をしています。

;;; define-method-combinationの短いフォームの例
 
(define-method-combination and :identity-with-one-argument t)
 
(defmethod func and ((x class1) y) ...)
 
;;; このサンプルと同等の長いフォームの例:
 
(define-method-combination and
        (&optional (order :most-specific-first))
        ((around (:around))
         (primary (and) :order order :required t))
  (let ((form (if (rest primary)
                  `(and ,@(mapcar #'(lambda (method)
                                      `(call-method ,method))
                                  primary))
                  `(call-method ,(first primary)))))
    (if around
        `(call-method ,(first around)
                      (,@(rest around)
                       (make-method ,form)))
        form)))
 
;;; define-method-combinationの長いフォームの例
 
;The default method-combination technique
(define-method-combination standard ()
        ((around (:around))
         (before (:before))
         (primary () :required t)
         (after (:after)))
  (flet ((call-methods (methods)
           (mapcar #'(lambda (method)
                       `(call-method ,method))
                   methods)))
    (let ((form (if (or before after (rest primary))
                    `(multiple-value-prog1
                       (progn ,@(call-methods before)
                              (call-method ,(first primary)
                                           ,(rest primary)))
                       ,@(call-methods (reverse after)))
                    `(call-method ,(first primary)))))
      (if around
          `(call-method ,(first around)
                        (,@(rest around)
                         (make-method ,form)))
          form))))
  
;どれかがnon-nilを返却するまでメソッドを実行する単純な例
(define-method-combination or ()
        ((methods (or)))
  `(or ,@(mapcar #'(lambda (method)
                     `(call-method ,method))
                 methods)))
  
;先行のより完成されたバージョン
(define-method-combination or
        (&optional (order ':most-specific-first))
        ((around (:around))
         (primary (or)))
  ;; order引数の処理
  (case order
    (:most-specific-first)
    (:most-specific-last (setq primary (reverse primary)))
    (otherwise (method-combination-error "~S is an invalid order.~@
    :most-specific-first and :most-specific-last are the possible values."
                                         order)))
  ;; プライマリメソッドは必要
  (unless primary
    (method-combination-error "A primary method is required."))
  ;; プライマリメソッドを呼び出すフォームの構築
  (let ((form (if (rest primary)
                  `(or ,@(mapcar #'(lambda (method)
                                     `(call-method ,method))
                                 primary))
                  `(call-method ,(first primary)))))
    ;; aroundメソッドを囲むフォーム
    (if around
        `(call-method ,(first around)
                      (,@(rest around)
                       (make-method ,form)))
        form)))
  
;オプション:orderと:requireを使った同じ例
(define-method-combination or
        (&optional (order ':most-specific-first))
        ((around (:around))
         (primary (or) :order order :required t))
  (let ((form (if (rest primary)
                  `(or ,@(mapcar #'(lambda (method)
                                     `(call-method ,method))
                                 primary))
                  `(call-method ,(first primary)))))
    (if around
        `(call-method ,(first around)
                      (,@(rest around)
                       (make-method ,form)))
        form)))
  
;この短いフォームの呼出しは先行と同一のふるまいをする
(define-method-combination or :identity-with-one-argument t)
 
;qualifiersの正の整数によるメソッドの順序付け
;この小さな例では:aroundメソッドは許されない
(define-method-combination example-method-combination ()
        ((methods positive-integer-qualifier-p))
  `(progn ,@(mapcar #'(lambda (method)
                        `(call-method ,method))
                    (stable-sort methods #'<
                      :key #'(lambda (method)
                               (first (method-qualifiers method)))))))

(defun positive-integer-qualifier-p (method-qualifiers)
  (and (= (length method-qualifiers) 1)
       (typep (first method-qualifiers) '(integer 0 *))))
  
;;; 引数:argumentsの使用例
(define-method-combination progn-with-lock ()
        ((methods ()))
  (:arguments object)
  `(unwind-protect
       (progn (lock (object-lock ,object))
              ,@(mapcar #'(lambda (method)
                            `(call-method ,method))
                        methods))
     (unlock (object-lock ,object))))

影響

なし。

副作用

コンパイラーはコンパイル時の副次的な処理を行う必要はありません。

例外

短いフォームで定義されたmethod-combinationの型は、 メソッドに対して正確にひとつの修飾子を要求します。 もし適用可能なメソッドに、修飾子がなかったり、 method-combinationの型がサポートされていない 修飾子であったときは、 型errorのエラーが発生します。 少なくともひとつのプライマリメソッドが適用可能でないと 型errorのエラーが発生します。

もしどのメソッドグループにも属さない適用可能なメソッドがある場合は、 システムは、型errorのエラーを通知し、 そのメソッドが使用中のmethod-combinationの種類に対して無効であることを示します。

もし:requireオプションの値がtrueであり、かつメソッドグループが空のとき (これは、適用可能なメソッドが、qualifier-patternにマッチしないか あるいはpredicateを満たさなかったとき) 型errorのエラーが発生します。

もしorder引数が評価された値が、 :most-specific-first:most-specific-lastの どちらでもなかった場合は型errorのエラーが発生します。

参考

call-method, call-next-method, documentation, method-qualifiers, method-combination-error, invalid-method-error, defgeneric, 7.6.6. メソッドの選択とコンビネーション, 7.6.6.4. 組み込みのMethod-Combination, 3.4.11. ドキュメント文字と宣言の文脈的な作用

備考

defgeneric:method-combinationオプションは、 ジェネリック関数が特定のmethod-combination型を使用するように 指定するときに使われます。 :method-combinationオプションの最初の引数はmethod-combination型の名前であり、 残りの引数はその型へのオプションです。


TOP, Github