Macro SHIFTF
shiftf place+ newvalue => old-value-1
place - place
newvalue - フォーム。評価されます。
old-value-1 - オブジェクト(最初のplaceの古い値)
shiftfは、各要素の値の変更を行いますが、 まずnewvalueを最後のplaceへ格納し、 そのあと2番目から最後までのplaceの値を残りのplaceにシフトします。
もしnewvalueが格納変数より多い値を生成したときは、余分な値は無視されます。 もしnewvalueが格納変数より少ない値しか生成しなかったときは、 値のないものはnilがセットされます。
フォームが(shiftf place1 place2 ... placen newvalue)のとき、 place1~placenまでの値を読み込み保存され、 そしてnewvalueが評価され、合計でn+1個の値が用意されます。 2~n+1個目の値は、それぞれplace1~placenに格納されます。 それは全てplaceフォームがシフトレジスタであるかのように扱われます。 newvalueは左からシフトされ、全ての値は左へひとつずつシフトされ、 そしてシフトから外されたplace1値が返却されます。
placeのサブフォームの評価については、5.1.1.1. placeのサブフォームの評価をご確認ください。
(setq x (list 1 2 3) y 'trash) => TRASH
(shiftf y x (cdr x) '(hi there)) => TRASH
x => (2 3)
y => (1 HI THERE)
(setq x (list 'a 'b 'c)) => (A B C)
(shiftf (cadr x) 'z) => B
x => (A Z C)
(shiftf (cadr x) (cddr x) 'q) => Z
x => (A (C) . Q)
(setq n 0) => 0
(setq x (list 'a 'b 'c 'd)) => (A B C D)
(shiftf (nth (setq n (+ n 1)) x) 'z) => B
x => (A Z C D)define-setf-expander, defsetf, *macroexpand-hook*
なし。
(shiftf place1 place2 ... placen newvalue)の効果は、だいたい次と同等です。
(let ((var1 place1)
(var2 place2)
...
(varn placen)
(var0 newvalue))
(setf place1 var2)
(setf place2 var3)
...
(setf placen var0)
var1)ただし、これは各placeのサブフォームを2度評価していますが、 shiftfはただ一度だけです。 例えば、下記の通り。
(setq n 0) => 0
(setq x (list 'a 'b 'c 'd)) => (A B C D)
(prog1 (nth (setq n (+ n 1)) x)
(setf (nth (setq n (+ n 1)) x) 'z)) => B
x => (A B Z D)