如何在Common Lisp中编写宏定义宏

10

我在我的代码库中有大约两个宏(数量还在增加),看起来像这样:

(defmacro def-stat-method (method-name stat)
  `(progn
     (defmethod ,method-name ((monster monster))
       (getf (stats monster) ,stat))
     (defmethod (setf ,method-name) (value (monster monster))
       (setf (getf (stats monster) ,stat) value))))

并且这个:

(defmacro def-energy-method (method-name stat)
  `(progn
     (defmethod ,method-name ((monster monster))
       (getf (energies monster) ,stat))
     (defmethod (setf ,method-name) (value (monster monster))
       (setf (getf (energies monster) ,stat) value))))
每个宏都具有以下调用语法:(def-stat-method ranged-weapon :ranged-weapon)
我想要一个宏(def-foo-method macro-name method),以便将(def-foo-method def-stat-method stats)扩展为上面的第一个示例。我是Lisp的新手,不太知道该怎么做。感谢任何帮助。
2个回答

13

只需编写一个宏,该宏扩展为另一个defmacro,像这样:

(defmacro def-foo-method (macro-name method)
  `(defmacro ,macro-name (method-name stat)
     (let ((method ',method))
       `(progn
          (defmethod ,method-name ((monster monster))
            (getf (,method monster) ,stat))
          (defmethod (setf ,method-name) (value (monster monster))
            (setf (getf (,method monster) ,stat) value))))))

我认为可能有一种方法可以不使用 let 来实现这个,但是嵌套反引号很令人困惑 :)


谢谢。我正在开发一个名为“矿井威胁”的GPL地牢游戏(http://motm.sourceforge.net/),只是想确认在其中加入这个是否符合您的要求。(我已经添加了归属注释) - krzysz00
2
对我来说没问题(抱歉回复晚了)。 - wdebeaum

2
对我来说,那段代码看起来很慢。面向对象的运行时派发再加上对属性列表的搜索?为什么要这样做?
有时会将属性列表添加到CLOS对象中,以提供存储不经常使用的插槽或使其易于扩展(可以在运行程序之前添加各种属性而无需知道它们)。通常最好将属性作为对象的实际插槽。

你是说整个plist的东西都应该被废弃,然后我应该获得更多的插槽。听起来是个不错的主意。 - krzysz00
4
将其作为普通的访问器可能是默认想法。如果您使用 plist,请问自己,为什么?如果您能自信地回答这个问题,那就继续。通常在Lisp中编码时,如果有时间进行设计迭代,应该查看代码并消除冗余。有时Lisp具有非常优雅的机制,如果没有,可以引入一个优雅的机制,以简化应用程序代码。 - Rainer Joswig

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接