我有一个 Common Lisp 类(class):
(defclass my-cool-class()
((variable1
:initarg :variable1
:accessor variable1
:initform (error "Must supply value to variable1"))
(variable2
:initarg :variable2
:accessor variable2
:initform (error "Must supply value to variable2"))
我想创建一个宏来简化这种打字的冗余
(defmacro make-slot (slot-name)
`(slot-name
:initarg :,slot-name
:accessor :,slot-name
:initform (error "Must supply value")))
最终我想拥有 (defclass my-cool-class () (make-slots '(foo bar baz)) 并自动将 foo、bar 和 baz 作为插槽取出。
但是,当我去做 make-slot 的
macroexpand-1
时,男孩,你好,我收到了读者错误。第一个是“冒号后的非法终止字符......”然后它继续前进。
SBCL 1.0.37。
编辑:示例在系统上在语法上是正确的,我在复制之前做了一些编辑。
六个月后——
(defun build-var (classname var)
(list var
:initform nil
:accessor (intern (concatenate 'string (string classname) "-"
(string var)))
:initarg (intern (string var) :keyword)))
(defun build-varlist (classname varlist)
(loop for var in varlist
collect (build-var classname var)))
(defmacro defobject (name &rest varlist)
"Defines a class with a set of behavior.
Variables are accessed by name-varname.
(defobject classname v1 v2 v3)
"
`(defclass ,name ()
,(build-varlist name varlist))):
两年半后。
我在其他地方发现了六个月大的代码。虽然我很受宠若惊,但它也提醒我更新这个。
如果您喜欢这个想法,我会将这段代码保存在: https://github.com/pnathan/defobject 。和以前一样,它的目标是生成重复输入最少的 CLOS 类。存在一个类似的系统,称为 DEFCLASS-STAR。建议有兴趣的各方审查两者。
最佳答案
您不能将宏放在您想要的代码中。 阅读 CLHS 中结构的语法。
例如你不能这样做:
(defun foo (make-arg-list 'a 'b) a b)
DEFUN 需要 arglist 而不是创建 arglist 的函数。
Lisp 扩展宏,其中需要 Lisp 形式。在需要其他列表(例如插槽列表)的地方,Lisp 不会宏展开。
类似的 DEFCLASS 需要一个插槽列表,而不是一个创建插槽列表的函数。
与插槽列表类似,DEFCLASS 期望每个插槽是一个名称或一个描述插槽的列表。
查看 DEFCLASS 的语法:
http://www.lispworks.com/documentation/HyperSpec/Body/m_defcla.htm
你也不能把逗号放在你想要的地方。
也许一本基本的 Lisp 书可能会有所帮助。阅读 Lisp 语法。
:,foo
以上意义不大。
逗号运算符将项目放入反引号列表中。它不会将项目放入符号中。
如果要创建符号,则需要调用 INTERN 或 MAKE-SYMBOL。
解决方案
编写一个 MY-DEFCLASS 宏,允许使用更短的语法并扩展为 DEFCLASS。已经有 DEFCLASS* 宏在库中做类似的事情。
关于macros - defmacro 和 defclass,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/3868658/