2012-07-13 74 views
0

從這個問題引發了關於SETF擴展:defining setf-expanders in Common LispCommon Lisp的:方法定義SETF擴展時,儘量減少重複代碼

當編寫用戶定義的干將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> 

注(汽車LST)的形式,在已定義一個SETF擴展的實際訪問,如何在這兩個defuns。這一直讓我有些惱火。能夠在第一個defun上說出'是好的,'嘿,我正在定義一個defun,這是一個吸氣,但我也希望它有一個典型的setf擴張器'。

用普通的lisp標準來表達這個嗎?有沒有其他人擔心這個問題,並定義了一個這樣做的宏?

爲了清楚起見,我想在這裏定義一個getter和典型的setter,其中getter編譯到已經有setter(例如car lst)的通用lisp窗體的方式是隻在代碼中寫過一次。

我也明白有些時候你不想這樣做,B/C設置者需要在設置值之前執行一些副作用。或者它是一個實際設置多個值或其他值的抽象。這個問題在那種情況下不那麼重要。我在這裏談論的是這樣一種情況,即制定者做標準事情,並設定獲取者的位置。

回答

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)) 

宏的詳細信息可以在彼得·塞貝爾的書,Practical Common Lisp被發現。 Paul Graham的書「ANSI Common Lisp」的第10章是另一個參考。

+0

是的;這有效;我會稍微等一下,看看我是否有其他的實現。 – 2012-07-14 05:50:06

0

馬克的做法,雷納的崗位上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) 

這裏有一些變量捕捉問題在生產代碼中使用這個宏之前,可能應該注意。