まくろちゃれんじ!setf編(第五話)

setfを、get-setf-expansionを用いて書いてみよう!という目標を立てていたのが本連載、「まくろちゃれんじ!setf編」ですが、どうやら今回は成功したようです。
参考サイトはここ→[代入を簡略化するマクロ]
上記サイトのour-pushの論理をほとんどそのまま使っています。

(defmacro my-setf (place obj)
  (multiple-value-bind (vars argvs val setter accessor)
      (get-setf-method place)
    `(let ,(mapcar #'list vars argvs)
       (let ((,@val ,obj))
	 ,setter))))

get-setf-expansionを使っていないのは、これをテストしていた環境がたまたまxyzzyだったから。SLIME上でやろうとも思ったんだけど、メモをWindows上に置いていたので面倒だったんだ。
さて、これを用いると、

> (defvar x '(1 2 3 4 5 6))
x
> (my-setf (cadr x) 1000)
1000
> x
(1 1000 3 4 5 6)
> (my-setf (cadddr x) 2000)
2000
> x
(1 1000 3 2000 5 6)

こんな感じにきちんと動いていることが分かる。


ところが展開形は、

> (macroexpand-1 '(my-setf (cadr x) 1000))
(let ((#1=#:G9 x))
  (let ((#2=#:G10 1000))
    (progn (rplaca (cdr #1#) #2#) #2#)))
t

> (macroexpand-1 '(setf (cadr x) 1000))
(progn (rplaca (cdr x) 1000) 1000)
t

ご覧のとおり、本当のsetfとは異なる形になってしまっている。
ここの載せ替えが出来ないと、きちんと出来たとは言い難い。


けど今日はもう思いつかないので、これにて。
(get-setf-expansionメソッドから返る四つ目の式に変更を施せないと#1#などの変数だけ評価するってことが出来ない、というところにつまづいてしまう。実装依存も良くないので、/#[1-9]#/にヒットする要素のみ評価、とかするわけにも行かないだろうし、難しい)