まくろちゃれんじ!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]#/にヒットする要素のみ評価、とかするわけにも行かないだろうし、難しい)