#:g1: 実践SETF定義: #'(setf foo)篇

Posted 2018-12-03 16:50:53 GMT

Lisp SETF Advent Calendar 2018 4日目 》

どうもsetf機構についてどんどんマイナーな方向に進んでしまいそうなので、実践的なものも挟んでいきたいと思います。

Common Lispでのsetfの定義方法と定義構文ですが、やたらと数が多いです。
しかも、省略形式と、詳細形式に分かれていたりして、一体何を使ったら良いのかと思うこともままあります。

ざっと一覧にすると、

加えて、定義時に使う補助関数として、get-setf-expansionがあります。

今回は、上記から、(defun/defmethod (setf ...)) を解説したいと思います。

(defun/defmethod (setf ...))

(defun/defmethod (setf ...)) の形式は、CLtL1には存在しておらず、ANSI CLになってから追加されたものです。

追加の目的ですが、メソッドのアクセサをdefmethodで定義させたいためです。

(defclass foo ()
  (a b c))

(defmethod (setf foo-a) (val (obj foo)) (setf (slot-value obj 'a) val))

こんな感じのことがしたいという訳ですが、ANSI CLでは、この為に関数名を拡張して、(setf foo)というような名前も使えるようにしました。
なお、この形式の関数名はsymbol-functionでは扱えないのでfdefinitionを利用します。(専らfdefinitionを使っておけば良いのですが)

(funcall #'(setf foo-a) 42 (make-instance 'foo))
→ 42

(setf (foo-a (make-instance 'foo)) 42) → 42

(fdefinition '(setf foo-a)) → #<standard-generic-function (setf foo-a) 40E01CBF4C>

単なる関数/メソッドなので、setfとは関係ないこともできてしまいますが、当然ながら、これはスタイル上良くないこと、とされています。

(defun (setf foo) (val var)
  (list var val))

(setf (foo 'var) 'val)(var val)

なお、処理系が標準関数のsetfの実装をマクロにするか関数にするかは任意なので、関数で書けるからといって、

(funcall #'(setf car)...)

のような書き方をしても可搬性は期待できません。
個人的には良くやってしまうミスなのですが、統一して欲しい……。

アドベントカレンダーもまだまだ残りの日数がありますので、今後もsetfの定義のバリエーションについて書いていきます。


HTML generated by 3bmd in LispWorks 7.0.0

comments powered by Disqus