fu7mu4’s diary

はてなダイアリーから移転しました。

defun の関数名にあたるところに setfが入っている、SETF関数の宣言のメモ

いろいろと、あちらこちらで、Common lispソースコードを見ていると、こんなものに出会った。

(defun (setf car) (new-car lst)
  (rplaca lst new-car)
  new-car)
(defun cookies-out* (&optional (reply *reply*))
"Returns an alist of the outgoing cookies associated with the REPLY object REPLY."
    (cookies-out reply))

(defun (setf cookies-out*) (new-value &optional (reply *reply*))
"Sets the alist of the outgoing cookies associated with the REPLY object REPLY."
    (setf (cookies-out reply) new-value))

defunの関数名のところに、setfが入っている。なんだろう?
いろいろ見ていると、classを作成したときの、アクセス関数などで使用される、SETF関数の定義だということだった。


実践Common Lisp の17.4章にある説明によると、

(defun bank-account ()
   ((customer-name
     :initarg :customer-name
     :initform (error "Must supply a customer name"))
    (balance
     :initarg :balance
     :initform 0)
    (account-number
     :initform (incf *account-numbers*))
    account-type))

こんなクラス定義があったとすると、
SLOT-VALUE関数でアクセスできるらしい。
balance スロット*1のReader関数はこうなる。

(defun balance (account)
   (slot-value account 'balance))

それで、このSLOT-VALUE関数を使わない方法としてSETF関数というのがあった。(らしい)

;;; 定義
(defun (setf customer-name) (name account)
   (setf (slot-value account 'customer-name) name))
;;; 使用方法
(setf (customer-name my-account) "fu7mu4") ; name("fu7mu4") を account(my-account)に設定するようになる。

ふふーん。
この書き方の説明のあとで、DEFCLASSの宣言時にアクセサ関数を同時に宣言してしまう方法があったので完全に忘れていた。

*1:通常の言葉ではクラスのメンバ