Lisp 关于保存宏/函数调用的任何提示?

Lisp 关于保存宏/函数调用的任何提示?,lisp,common-lisp,Lisp,Common Lisp,不久前,我写了一个基于动物园的小例子,我写了一个基类ANIMAL,一些子类CAT,MOUSE,等等。一个通用方法FEED包含一个动物参数和一些专门针对每个动物子类型的方法 在编写了第二个和第三个类之后,方法对我意识到我在一遍又一遍地编写同样的东西,并决定编写一个宏DEF-ANIMAL-SUBCLASS,它扩展为一个PROGN,定义了新的子类和相应的方法 然后我意识到我刚刚给了我的用户一种定义他们自己的动物子类型的方法,他们可能会发现这很有用!然而,虽然他们可能只是在运行的图像中这样做,但我没有办

不久前,我写了一个基于动物园的小例子,我写了一个基类ANIMAL,一些子类CAT,MOUSE,等等。一个通用方法FEED包含一个动物参数和一些专门针对每个动物子类型的方法

在编写了第二个和第三个类之后,方法对我意识到我在一遍又一遍地编写同样的东西,并决定编写一个宏DEF-ANIMAL-SUBCLASS,它扩展为一个PROGN,定义了新的子类和相应的方法

然后我意识到我刚刚给了我的用户一种定义他们自己的动物子类型的方法,他们可能会发现这很有用!然而,虽然他们可能只是在运行的图像中这样做,但我没有办法保存他们的新动物类型,以便在图像重新启动时,为他们重新创建任何新的动物类型(他们不必重新计算宏)

有没有一个常规的方法来做这件事

这是不应该做的事情吗

如有任何提示,我们将不胜感激

干杯


p

执行此操作的传统方法是使用数据库来存储您的动物亚类。选择一个,连接CLSQL,让它以一种您可以解释回它们各自定义的格式存储动物记录

根据规模和部署情况,您也可以在平面文件中处理它


也就是说,除了定义一个新的子类和方法外,让您的
def animal子类
将它们的
def…
语句序列化到一个单独的
.lisp
文件中。然后,程序将在处理其配置时加载该文件。(但一定要仔细考虑一下。例如,如果用户定义了一个已经存在的动物子类,会发生什么情况?)看看Emacs如何存储一些想法的自定义设置。

Common Lisp是一种基于图像的语言,因此,除了Inaimathi的回答中给出的解决方案外,您还可以保存图像,如果您重新启动它,所有用户定义的类(以及其他状态,网络连接等短暂的事物除外)都将存在

如何做到这一点取决于您的CL实现,因此您必须检查其文档。CCL使用、SBCL、CLISP等


当然,选择哪种方法(Inaimathi建议的方法之一或保存图像)取决于您的应用程序和需要,因为每种方法都有不同的优点和缺点。

如果您使用宏定义动物类,则可以让宏记录源代码

(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))
示例(在LispWorks中工作):

例如,我们可以使用列表将源代码存储在类分配的插槽中。 或者,您可以只使用一个简单的全局变量

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

一个简单的
阅读
就会把它带回来。

你的问题不清楚。你在这里开发什么样的软件?听上去,您正在为编程制作实用程序(一个宏和类的小库)。如果是这种情况,那么在映像重新启动时重新加载所有定义的责任将由程序员承担。如果您在REPL中定义了内容,但没有将其保存到任何位置,那么退出映像,则这些内容将丢失。不仅是动物亚类,还有一切。函数,defvars,…感谢您的所有评论;这个问题有点假设性,也许需要一点背景知识!我已经用Java编写了一个解决方案,但决定看看是否可以用Lisp编写一个解决方案。一旦我这样做了,我就开始思考,如果我在用户中部署了这样一个Lisp解决方案,我将如何处理这些新定义?我想知道是否有一些传统的方法可以做到这一点。保存图像是我没有想到的一个解决方案!谢谢。我正在使用SBCL,可惜它缺少CLASS_原型!:(然而,我怀疑在文件中写入一些内容会读作PROGN-谢谢。@彼得:使用SBCL,函数CLASS-PROTOTYPE在包SB-MOP中。但是你可以使用类名ANIMAL。它是一个符号。只需将源代码列表放在其属性列表上。感谢指针-give)如果我能找到这个班的资料来源,我对写程序的评论是多余的。我想我需要好好想想!