Macro DEFINE-SETF-EXPANDER

UP


Macro DEFINE-SETF-EXPANDER

Macro DEFINE-SETF-EXPANDER

構文

define-setf-expander access-fn lambda-list [[declaration* | documentation]] form*
=> access-fn

引数と戻り値

access-fn - 関数かマクロの名前のシンボル
lambda-list - マクロラムダリスト
declaration - 宣言式。評価されません。
documentation - 文字列。評価されません。
form - 暗黙のprogn

定義

define-setf-expanderは、setfaccess-fnにより参照された placeを更新する手段を指定します。

setfは、placeaccess-fnという語と placeへの新しい値が指定されたとき、 適切に更新を行うためのフォームを展開します。

lambda-listは、分割のラムダリストをサポートします。 3.4.4. マクロのラムダリストをご確認ください。

documentationは、ドキュメント文字として種類setfaccess-fnに割り当てられます。

formはsetf-expanderの定義を構成し、 setfが呼び出されplaceaccess-fnが与えられたときは そのsetf-expanderを計算しなければなりません。 setf-expander関数は、 define-setf-expanderフォームが現れる 同じレキシカルな環境によって定義されます。 formが実行されている間、lambda-list内の変数は、 placeフォームの部分に束縛されます。 define-setf-expanderフォームの lambda-list以外のformであるボディ部は、 暗黙的にaccess-fnという名前のblockで囲まれます。

formの評価は、5.1.1.2. Setfの展開で定義されたような 5つの値を返却しなければなりません。

もしdefine-setf-expanderフォームがトップレベルフォームとして現れたときは、 コンパイラは、そのファイルの後でsetfが呼ばれたときに展開が行われるよう、 setf-expanderを有効にしなければなりません。 もし同じファイルの後でplaceaccess-fnを使用するときは、 プログラマーは、formをコンパイル時に 評価できることを保証しなければなりません。 コンパイラーは、get-setf-expansionの環境引数が マクロの環境パラメータの値を受け取った場合、 コンパイル時にこれらのsetf-expanderを 利用できるようにしなければなりません。

例文

(defun lastguy (x) (car (last x))) =>  LASTGUY
(define-setf-expander lastguy (x &environment env)
  "Set the last element in a list to the given value."
  (multiple-value-bind (dummies vals newval setter getter)
      (get-setf-expansion x env)
    (let ((store (gensym)))
      (values dummies
              vals
              `(,store)
              `(progn (rplaca (last ,getter) ,store) ,store)
              `(lastguy ,getter))))) =>  LASTGUY
(setq a (list 'a 'b 'c 'd)
      b (list 'x)
      c (list 1 2 3 (list 4 5 6))) =>  (1 2 3 (4 5 6))
(setf (lastguy a) 3) =>  3
(setf (lastguy b) 7) =>  7
(setf (lastguy (lastguy c)) 'lastguy-symbol) =>  LASTGUY-SYMBOL
a =>  (A B C 3)
b =>  (7)
c =>  (1 2 3 (4 5 LASTGUY-SYMBOL))
;;; (LDB bytespec int)フォームののset-expander。
;;; intフォームは自身をSETFで適切に扱います。
(define-setf-expander ldb (bytespec int &environment env)
  (multiple-value-bind (temps vals stores
                         store-form access-form)
      (get-setf-expansion int env) ; intのsetf-expander取得
    (let ((btemp (gensym))     ;byte指定子の一時変数
          (store (gensym))     ;byteを保存する一時変数
          (stemp (first stores))) ;byteを保存する一時変数
      (if (cdr stores) (error "Can't expand this."))
;;; LDBのsetf展開の5つの返却値
      (values (cons btemp temps)       ;一時変数
              (cons bytespec vals)     ;フォームの値
              (list store)             ;保存の変数
              `(let ((,stemp (dpb ,store ,btemp ,access-form)))
                 ,store-form
                 ,store)               ;保存するフォーム
              `(ldb ,btemp ,access-form) ;アクセスするフォーム
             ))))

影響

なし。

例外

なし。

参考

setf, defsetf, documentation, get-setf-expansion, 3.4.11. ドキュメント文字と宣言の文脈的な作用

備考

define-setf-expanderdefsetfの長いフォームとの違いは、 本体を実行しているときのplaceフォームの部分で lambda-listの変数の束縛が、 そのような部分の値を一時変数に束縛してないところです。 さらにdefine-setf-expanderは、 defsetfの制限である access-fnが関数か関数のようなマクロである必要はなく、 lambda-listdefmacroのような 任意の分配のパターンが許されます。


TOP, Github