0

setf expanders に関するこの質問からトリガーされました: Common Lisp での setf-expanders の定義

ユーザー定義ゲッターの setf エクスパンダーを作成する場合、プロパティの取得方法に関する限り、ゲッターとセッターにコードの重複があることがよくあります。例えば:

CL-USER>
(defun new-car (lst)
  (car lst))
NEW-CAR
CL-USER> 
(defun (setf new-car) (new-value lst)
  (setf (car lst) new-value))
(SETF NEW-CAR)
CL-USER> 
(defparameter *lst* (list 5 4 3))
*LST*
CL-USER> 
*lst*
(5 4 3)
CL-USER> 
(setf (new-car *lst*) 3)
3
CL-USER> 
*lst*
(3 4 3)
CL-USER> 

(car lst) 形式、setf エキスパンダーが既に定義されている実際のアクセサーが両方の defun にあることに注意してください。これはいつも私をいくらか悩ませてきました。最初の defun で、「getter である defun を定義していますが、典型的な setf エクスパンダも必要です」と言うことができればよいでしょう。

これを表現するための一般的なLisp標準を使用する方法はありますか? 他の誰かがこの問題を心配して、これを行うマクロを定義しましたか?

明確にするために、ここで私が望むのは、ゲッターと典型的なセッターを定義する方法です。ここで、ゲッターが既にセッターを持っている一般的な Lisp フォーム ((car lst) など) にコンパイルされる方法は、コード。

また、これを行いたくない場合があることも理解しています。b/c セッターは、値を設定する前にいくつかの副作用を実行する必要があります。または、実際に複数の値を設定する抽象化などです。この質問は、その状況では関連性が低くなります。ここで話しているのは、setter が標準的なことを行い、getter の場所を設定するだけの場合です。

4

3 に答える 3

4

マクロを使用すると、目的を達成できます。

(defmacro define-place (name lambda-list sexp)
  (let ((value-var (gensym)))
    `(progn
       (defun ,name ,lambda-list
         ,sexp)

       (defun (setf ,name) (,value-var ,@lambda-list)
         (setf ,sexp ,value-var)))))

(define-place new-chr (list)
  (car list))

マクロの詳細については、Peter Seibel の著書Practical Common Lispを参照してください。Paul Graham の著書「ANSI Common Lisp」の第 10 章も参考になります。

于 2012-07-14T05:41:51.620 に答える
0

Mark のアプローチ、Rainer のmacro-functionに関する投稿、および Amalloy のtransparent macroletに関する投稿から作業して、私はこれを思いつきました。

(defmacro with-setters (&body body)
  `(macrolet ((defun-mod (name args &body body)
                `(,@(funcall (macro-function 'defun)
                             `(defun ,name ,args ,@body) nil))))
     (macrolet ((defun (name args &body body)
                  `(progn
                     (defun-mod ,name ,args ,@body)
                     (defun-mod (setf ,name) (new-val ,@args)
                                (setf ,@body new-val)))))
       (progn
         ,@body))))

使用するには:

Clozure Common Lisp Version 1.8-r15286M  (DarwinX8664)  Port: 4005  Pid: 41757
; SWANK 2012-03-06
CL-USER>
(with-setters
 (defun new-car (lst)
    (car lst))
 (defun new-first (lst)
    (first lst)))
(SETF NEW-FIRST)
CL-USER>
(defparameter *t* (list 5 4 3))
*T*
CL-USER>
(new-car *t*)
5
CL-USER>
(new-first *t*)
5
CL-USER>
(setf (new-first *t*) 3)
3
CL-USER>
(new-first *t*)
3
CL-USER>
*t*
(3 4 3)
CL-USER>
(setf (new-car *t*) 9)
9
CL-USER>
*t*
(9 4 3)

このマクロを製品コードで使用する前に、おそらく注意が必要な変数キャプチャの問題がいくつかあります。

于 2012-07-14T07:05:45.447 に答える