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
`(lastguy ,getter))))) setq a (list 'a 'b 'c 'd)
(list 'x)
b (list 1 2 3 (list 4 5 6))) => (1 2 3 (4 5 6))
c (setf (lastguy a) 3) => 3
(setf (lastguy b) 7) => 7
(setf (lastguy (lastguy c)) 'lastguy-symbol) => LASTGUY-SYMBOL
(=> (A B C 3)
a => (7)
b => (1 2 3 (4 5 LASTGUY-SYMBOL))
c ;;; (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指定子の一時変数
(gensym)) ;byteを保存する一時変数
(store (first stores))) ;byteを保存する一時変数
(stemp (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
のような 任意の分配のパターンが許されます。