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

pet*_*ter 3 lisp common-lisp

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

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

然后我意识到我刚刚给了我的用户一种定义他们自己的ANIMAL子类型的方法,他们可能觉得这些子类很有用!然而,虽然他们可能只是在正在运行的图像中执行此操作,但我没有办法保存其新的ANIMAL类型,以便在重新启动图像的情况下,将为它们重新创建任何新的ANIMAL类型(没有他们必须重新评估宏).

有这样做的传统方式吗?

这是不应该做的事情?

任何提示都会感激不尽!

干杯,

P

Rai*_*wig 7

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

示例(适用于LispWorks):

我们可以使用alist将源代码存储在类分配的槽中.或者,您可以使用一个简单的全局变量.

(defclass animal ()
  ((source :allocation :class :initform nil)))
Run Code Online (Sandbox Code Playgroud)

上面有一个插槽,应该指向类名和源代码的列表.

(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))
Run Code Online (Sandbox Code Playgroud)

生成的代码是什么样的?

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)
Run Code Online (Sandbox Code Playgroud)

使用它:

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")))
Run Code Online (Sandbox Code Playgroud)

因此,只要使用宏,就会记录最后的源代码DEF-ANIMAL-CLASS.然后,您可以将代码写入文件:

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

一个简单的READ回归.


Ina*_*thi 5

这样做的传统方法是使用数据库来存储动物子类.选择一个,连接CLSQL并让它以一种格式存储动物记录,您可以将其解释回各自的定义.

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

也就是说,除了定义新的子类和方法之外,还要将def-animal-subclass它们的def...语句序列化为单独的.lisp文件.然后,您的程序将在处理其配置的位置加载该文件.(请务必仔细考虑一下.例如,如果您的用户定义了已存在的动物子类,会发生什么?)看看Emacs如何为某些想法存储自定义.