2012-05-16 67 views
3

前段時間,對於一個基於動物園的小例子,我編寫了一個基類ANIMAL,一些子類CAT,MOUSE等等,這是一個通用方法FEED,它採用ANIMAL參數和一些專用於每個ANIMAL子類型的方法。有關保存宏/函數調用的任何提示?

寫完第二和第三課之後,我意識到我一遍又一遍地寫同樣的東西,決定編寫一個擴展爲PROGN的宏DEF-ANIMAL-SUBCLASS,它定義了新的子類和適當的方法。

然後我意識到,我剛剛給我的用戶定義自己的動物亞種,東西的方式,他們可能會發現有用!但是,雖然它們可能只是在運行的圖像中執行此操作,但我沒有保存其新ANIMAL類型的方法,因此,如果圖像重新啓動,將爲它們重新創建任何新的ANIMAL類型(沒有他們必須重新評估宏)。

有沒有這樣做的傳統方式?

這是不該做的事情嗎?

任何提示將受到感謝!

乾杯,

P

+1

你的問題不清楚。你在這裏開發什麼樣的軟件?從它的聲音中,你正在編寫實用程序(一個宏和類的小庫)。如果是這樣的話,當圖像重新啓動時重新加載所有定義的責任被理解爲由程序員決定。如果你在REPL中定義了一些東西,並且不把它們保存到任何地方,那麼退出圖像,它們就會丟失。不僅動物的子類,而且包括一切。功能,defvars,... – Kaz

+0

謝謝你的所有意見;這個問題是有點假設的,也許會有一點背景!我已經用Java編寫了一個解決方案,但決定看看我能否在Lisp中編寫解決方案。一旦我這樣做了,我就開始思考,如果我和一個用戶部署了這樣的一個Lisp解決方案,我將如何處理這些新的定義?我想知道是否有一些傳統的做法。 – peter

回答

7

如果您使用宏定義您的動物類,那麼您可以讓宏記錄源代碼。

實施例(在LispWorks作品):

我們可以使用ALIST例如源代碼存儲在一個類分配的時隙。 或者,你可以只使用一個簡單的全局變量。

(defclass animal() 
    ((source :allocation :class :initform nil))) 

上面有一個插槽,它應該指向類名和源代碼的列表。

(defmacro def-animal-class (&whole code name feeding) 
    `(progn 
    (defclass ,name (animal)()) 
    (defmethod feed ((animal ,name)) ,@feeding) 
    (let ((item (assoc ',name 
         (slot-value (class-prototype (find-class 'animal)) 
            'source)))) 
     (if item 
      (setf (cdr item) ',code) 
     (setf (slot-value (class-prototype (find-class 'animal)) 
          'source) 
       (list (cons ',name ',code))))) 
    ',name)) 

生成的代碼是什麼樣的?

CL-USER > (pprint (macroexpand-1 '(def-animal-class cat ((print "feeding a cat"))))) 

(PROGN 
    (DEFCLASS CAT (ANIMAL) NIL) 
    (DEFMETHOD FEED ((ANIMAL CAT)) (PRINT "feeding a cat")) 
    (LET ((ITEM (ASSOC 'CAT (SLOT-VALUE (CLASS-PROTOTYPE (FIND-CLASS 'ANIMAL)) 
             'SOURCE)))) 
    (IF ITEM 
     (SETF (CDR ITEM) '(DEF-ANIMAL-CLASS CAT ((PRINT "feeding a cat")))) 
     (SETF (SLOT-VALUE (CLASS-PROTOTYPE (FIND-CLASS 'ANIMAL)) 'SOURCE) 
      (LIST (CONS 'CAT '(DEF-ANIMAL-CLASS CAT ((PRINT "feeding a cat")))))))) 
    'CAT) 

使用它:

CL-USER 75 > (def-animal-class cat ((print "feeding a cat some more"))) 
CAT 

CL-USER 76 > (cdr (first (slot-value (class-prototype (find-class 'animal)) 
            'source))) 

(DEF-ANIMAL-CLASS CAT ((PRINT "feeding a cat some more"))) 

因此最後的源代碼被記錄,每當一個使用宏DEF-ANIMAL-CLASS。 然後可以例如代碼寫入文件:

(with-open-file (s "~/animals.sexp" :direction :output :if-exists :supersede) 
    (pprint (slot-value (class-prototype (find-class 'animal)) 'source) s)) 

一個簡單READ把它帶回。

+0

我曾經/正在使用SBCL,它很遺憾地缺少CLASS_PROTOTYPE! :(但是,我懷疑寫一些文件可能會導致讀作爲PROGN的問題太多 - 謝謝。 – peter

+0

@peter:with SBCL CLASS-PROTOTYPE函數在包SB-MOP中,但是你可以使用類名ANIMAL,它是一個符號,只需將源代碼列表放到它的屬性列表中 –

+0

感謝指針 - 考慮到我可以掌握類的源代碼, PROGN是多餘的,我想我需要讓我的頭繞着MOP! – peter

5

這樣的傳統方法是使用一個數據庫來存儲你的動物的子類。選擇一個,連接CLSQL並以可以解釋爲各自定義的格式存儲動物記錄。

根據規模和部署情況,你可能也逃脫只是處理它在一個平面文件。

也就是說,除了定義一個新的子類和方法外,請您的def-animal-subclass將它們的def...語句序列化爲單獨的.lisp文件。然後你的程序會在處理它的配置的時候加載這個文件。 (不過請務必仔細考慮,例如,如果用戶定義了一個已存在的動物子類,會發生什麼情況?)看看Emacs如何爲某些想法存儲自定義。

3

Common Lisp是一種基於圖像的語言,因此,除了Inaimathi的答案中給出的解決方案之外,您還可以保存圖像以及所有用戶定義的類(以及其他狀態,除了臨時性的東西網絡連接等)將在那裏,如果你重新啓動它。

如何做到這一點取決於你的CL實現,所以你必須檢查它的文檔。 CCL使用ccl:save application,SBCL sb-ext:save-lisp-and-die,CLISP ext:saveinitmem等。

以下哪些方法(由Inaimathi建議或保存圖像中的一種)要選擇取決於您的應用和需求,因爲它們每個方法都有不同的優點和缺點。

+1

保存圖像是一種解決方案,並沒有超越我的想法!謝謝。 – peter

+0

不客氣。 – danlei