#1 (defun (setf ) ...)

  • CLOS に興味がわいた、というか欲しくなった
  • closette というのは CLOS の subset らしい
  • 見てみたら2000行ちょいくらいだった
  • ふるい common-lisp らしいので読めそうな雰囲気だった
  • 「誰か移植しないかな」とかどっかで見かけた

とゆーわけでやってみる。

(defun (setf getf*) (new-value plist key)
  ...)

みたいなのをちょくちょく使ってるんだけど、xyzzy だとそんな関数名認めないとか怒られる。ちょっとググったりしたけどはっきりしたことがわからない。というか CLHS の defun には載ってなかったんで、ひょっとしたら今は使われてない書き方なのかも。

しょうがないので使ってるコードから本来の挙動を想像して実装してみた。

(setf (access-fn arg1 arg2) value)

としたときに defun-setf した関数に value arg1 arg2 が渡されるっぽい。

defsetf に関数渡すのと一緒かなと思ったのに引数の順番が違う(defsetf で設定する update-fn だと value が最後になる)。lambda-list の方をごにょごにょしようかと思ったけどどう考えても &rest とかめんどいので、引数の順番変えるだけの関数で包むことにした。

(defmacro closette::defun (name (&rest lambda-list) &body body)
  (if (and (consp name)
           (eq (car name) 'setf)
           (symbolp (cadr name))
           (null (cddr name)))
      (let ((access-fn (cadr name)))
        ;; from lisp/setf.l::defsetf
        `(eval-when (:compile-toplevel :load-toplevel :execute)
           (si:*putprop ',access-fn (lambda (&rest #1=#:args)
                                      (apply (lambda ,lambda-list ,@body)
                                             (append (last #1#) (butlast #1#))))
                        'lisp::setf-update)
           (si:*putprop ',access-fn ,(when (stringp #2=(car body)) #2#)
                        'lisp::setf-documentation)
           (remprop ',access-fn 'lisp::setf-lambda)
           (remprop ',access-fn 'lisp::setf-method)
           '(setf ,access-fn)))
    ;; from lisp/evalmacs.l::defun
    '(let ()
      (si:*fset ',name
                (si:*set-function-name
                 #'(lambda ,lambda-list ,@body)
                 ',name)))))

ところで移植ってふつーどうやるんだろう。とりあえず元のソースを xyzzy に喰わせてエラー吐いたりしたとこを修正してく方が楽かなぁと思いつつ、手動コピーしながら「これ動かねーだろ」と思ったとこを動くように変更したりしてる。