不久前,对于一个基于动物园的小例子,我写了一个基类ANIMAL,一些子类CAT,MOUSE等等。一个通用方法FEED采用ANIMAL参数和一些专门用于每个ANIMAL子类型的方法
在编写第二和第三类之后,方法对我意识到我一遍又一遍地写同样的东西并决定编写一个宏DEF-ANIMAL-SUBCLASS,它扩展为PROGN,定义了新的子类和适当的方法
然后我意识到我刚给了我的用户一种定义他们自己的ANIMAL子类型的方法,他们可能觉得这些子类很有用!然而,虽然他们可能只是在正在运行的图像中执行此操作,但我没有办法保存其新的ANIMAL类型,以便在重新启动图像的情况下,将为它们重新创建任何新的ANIMAL类型(没有他们必须重新评估宏。)
有传统方法吗?
是不是应该做的事情?
任何提示都会感激不尽!
干杯,
P
答案 0 :(得分: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
将它带回来。
答案 1 :(得分:5)
这样做的传统方法是使用数据库来存储动物子类。选择一个,挂钩CLSQL并让它以一种格式存储动物记录,你可以将它们解释回各自的定义。
根据规模和部署情况,您可能只是在平面文件中处理它。
也就是说,除了定义新的子类和方法之外,还要将def-animal-subclass
序列化其def...
语句到单独的.lisp
文件中。然后,您的程序将在处理其配置的位置加载该文件。 (请务必仔细考虑一下。例如,如果您的用户定义了已存在的动物子类,会发生什么?)看看Emacs如何为某些想法存储自定义。
答案 2 :(得分:3)
Common Lisp是一种基于图像的语言,因此,除了Inaimathi答案中给出的解决方案之外,您还可以保存图像和所有用户定义的类(以及其他状态,除了网络等短暂的内容)如果你重新启动它将会在那里。
如何执行此操作取决于您的CL实现,因此您必须检查其文档。 CCL使用ccl:save application
,SBCL sb-ext:save-lisp-and-die
,CLISP ext:saveinitmem
等。
当然,选择以下哪种方法(由Inaimathi建议或保存图像的方法之一)取决于您的应用和需求,因为每种方法都有不同的优点和缺点。