% 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
は、setf
がaccess-fnにより参照された
place
を更新する手段を指定します。
setf
は、place
にaccess-fnという語と
place
への新しい値が指定されたとき、
適切に更新を行うためのフォームを展開します。
lambda-listは、分割のラムダリストをサポートします。 3.4.4. マクロのラムダリストをご確認ください。
documentationは、ドキュメント文字として種類setf
で
access-fnに割り当てられます。
formはsetf-expanderの定義を構成し、
setf
が呼び出されplace
にaccess-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を有効にしなければなりません。
もし同じファイルの後でplace
がaccess-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-expander
の
defsetf
の長いフォームとの違いは、
本体を実行しているときのplace
フォームの部分で
lambda-listの変数の束縛が、
そのような部分の値を一時変数に束縛してないところです。
さらにdefine-setf-expander
は、
defsetf
の制限である
access-fnが関数か関数のようなマクロである必要はなく、
lambda-listにdefmacro
のような
任意の分配のパターンが許されます。