このパッケージはsetf
の他にも、汎変数に作用する多くのマクロを
定義する。placeが単に変数名である場合でも、多くは興味深く
有用である。
psetq
がsetq
に対応するように、このマクロはsetf
に
対応する: いくつかのplaceとformを含むとき、代入は
順次にではなく並列に起こる。つまり、すべての部分フォームは左から右へ
評価され、それからすべての代入が(未定義の順序で)行なわれる。
このマクロはplaceに格納されている数を1だけ、または指定されている
場合はxだけ増やす。増やされた値が戻される。たとえば、
(incf i)
は(setq i (1+ i))
と同等であり、
(incf (car x) 2)
は(setcar x (+ (car x) 2))
と同等である。
もう一度、評価の“明白な”順序を保存するために注意が払われる。たとえば、
(incf (aref vec (incf i)))
はi
を一度増やし、それからi
でアドレスされるvec
の
要素を増やすように現れる; これは実に正確にそれが行なうことであり、上の
フォームは“明らかな”展開と同等ではないことを意味し、
(setf (aref vec (incf i)) (1+ (aref vec (incf i)))) ; 間違い!
ではなく、むしろ何かより以下に似ているようなものである。
(let ((temp (incf i))) (setf (aref vec temp) (1+ (aref vec temp))))
もう一度、これらすべてはincf
や他の汎変数マクロによって自動的に
注意が払われる。
incf
のよりEmacs特有の例として、式(incf (point) n)
は(forward-char n)
と本質的に同等である。
このマクロはplaceに格納されている数を1だけ、または指定されている 場合はxだけ減らす。
このマクロはplaceに格納されているリストの最初の要素を取り除いて
戻す。それは
(prog1 (car place) (setf place (cdr place)))
に類似しているが、すべての部分フォームを一度だけ評価するように注意する
点が異なる。
このマクロはplaceに格納されるリストの先頭にxを挿入する。
それは(setf place (cons(コンス) x place))
に
類似しているが、部分フォームの評価が異なる。
このマクロはplaceに格納されているリストの先頭にxを
挿入するが、xがリストの存在するどの要素にもeql
でない
場合に限られる。
付加キーワード引数はadjoin
と同様に解釈される。
See 集合としてのリスト.
このマクロは左へ1つplaceをシフトし、newvalueの値(それは
単なる汎変数ではなく、どんなLisp式でもよい)をシフトして入れ、最初の
placeからシフトして出された値を戻す。したがって、
(shiftf a b c d)
は以下と同等だが
(prog1 a (psetf a b b c c d))
a、b、そしてcの部分フォームは明白な順序でそれぞれ 一度だけ実際には評価される点が異なる。
このマクロは循環的にplaceを左へ一つ回転する。したがって、
(rotatef a b c d)
は以下と同等だが
(psetf a b b c c d d a)
部分フォームの評価が異なる。rotatef
は常にnil
を戻す。
(rotatef a b)
はaとbを便利に
交換することに注意せよ。
下記のマクロはこのパッケージのために発明された; これらはCommon Lispに 類似するものはない。
このマクロはlet
に類似しているが、単なるシンボルではなく
汎変数用である。それぞれのbindingはフォーム
(place value)
であるべきである; placeの
オリジナルの内容はセーブされ、valueがそれらに格納され、それから
本体formが実行される。その後、placesはオリジナルの
セーブされた内容へ設定し戻される。この大掃除は、formが
throw
またはエラーのために正規でない脱出をした場合ですら起こる。
たとえば、
(letf (((point) (point-min)) (a 17)) ...)
はバッファの先頭へ現バッファの“ポイント”を動かし、17へa
を
束縛する(通常のlet
と同様だが、a
が単なる通常の
変数だからである)。本体が脱出した後、a
はそのオリジナルの値に
設定し戻され、ポイントはそのオリジナルの位置へ戻る。
(point)
のletf
はsave-excursion
とはあまり似ていない
ことに注意せよ。なぜなら後者はバッファ内の挿入と削除を追跡するマーカを
効果的にセーブするからである。実際は、(point-marker)
の
letf
はこの振る舞いにずっと近い(point
と
point-marker
はsetf
場所としては同等である; どちらも格納値
として整数かマーカを受け入れる)。
汎変数はリストのように見えるため、bindingとして‘(foo nil)’
のために‘foo’を使用するlet
の簡略表記法はletf
ではあいまいになるので許されていない。
しかし、binding指定子は1要素のリスト‘(place)’でもよく、
それは‘(place place)’に類似している。言い換えれば、
placeは本体へ入ることで乱されず、letf
の効果はその後
placeのオリジナルの値を戻すことだけである
((place place)
の例により示唆された冗長なアクセスと
格納は実際には起こらない)。
多くの場合、placeはletf
フォームに入るときによく定義された
値を持たなければならない。例外は単純変数とsymbol-value
や
symbol-function
への呼び出しだけである。入るときにシンボルが束縛
されていない場合、脱出時にmakunbound
またはfmakunbound
で
単に未束縛にされる。
let*
がlet
に対応するように、このマクロはletf
に対応
する: それは並列の順序ではなく順次に束縛を行なう。
これは“汎用”修正マクロである。functionを呼び出す。
functionは引用符のない関数名、マクロ名、または
ラムダでなければならない。引数としてplaceとargsを渡し、
placeへ結果を代入し戻す。たとえば、
(incf place n)
は(callf + place n)
と同じである。さらにいくつかの例:
(callf abs my-number) (callf concat (buffer-name) "<" (int-to-string n) ">") (callf union happy-people (list joe bob) :test 'same-person)
See setf独自化, define-modify-macro
、修正マクロのための幾分
簡潔な表記法を作るための方法。callf
は標準Common Lispへの拡張で
あることに再度注意せよ。
このマクロはcallf
に似ているが、placeが関数の第1ではなく
第2引数である点が異なる。たとえば、
(push x place)
は
(callf2 cons x place)
と同等である。
callf
やcallf2
マクロは、incf
、pushnew
、
そしてdefine-modify-macro
のような他のマクロのための
ビルディングブロックとして役に立つ。letf
やletf*
マクロは
シンボルマクロの処理に使われる; see マクロ束縛.