我正在尝试以下代码来编写一个宏,给定一个类的名称,自动创建一个具有name
实例变量的类,并以classname-name
的形式为其创建一个访问器。
(defmacro def-named-class (class-name)
`(defclass ,class-name ()
((name :accessor ,(intern (format nil "~A-~A" class-name "name"))
:initarg :name
:initform ""))))
这里的问题是,当宏运行时,例如使用参数foo
,访问器函数的名称为|FOO-name|
,但我希望它只是foo-name
}。原因是,(intern "foo-name")
会返回符号|foo-name|
。但是,如果我尝试使用普通函数执行相同的操作,请执行以下操作:
(defmacro def-hyp (name1 name2 arg-list &body body)
`(defun ,(intern (format nil "~A-~A" name1 name2))
,arg-list
,@body))
然后像(def-hyp foo name () 'foo-name)
一样调用它正确生成一个名为foo-name
的函数。所以我想知道是否有任何方法可以从第一个宏内的字符串表示中获取完全相同的符号。我正在使用Clozure CL。
答案 0 :(得分:3)
请注意,某个类已有名称。
CL-USER 19 > (defclass foo () ())
#<STANDARD-CLASS FOO 415040BE6B>
CL-USER 20 > (class-name *)
FOO
答案 1 :(得分:2)
通过继承更好地解决了吗?这是你的混音:
(defclass named ()
((name :initarg :name :accessor name-of)))
...您可以将它用于定义具有名称的对象的所有其他类:
(defclass this (named) ...)
(defclass that (named) ...)
答案 2 :(得分:1)
您应该将名称转换为大写:
(defmacro def-named-class (class-name)
`(defclass ,class-name ()
((name :accessor ,(intern (format nil "~A-~A" (string-upcase class-name) "NAME"))
:initarg :name
:initform ""))))
jkiiski的评论中提出的另一种可能性是仅更改格式字符串:
...
((name :accessor ,(intern (format nil "~:@(~A-~A~)" class-name "name"))
...
原因是Common Lisp阅读器的默认行为是在读取它时以大写形式转换任何符号。因此,当您编写foo-name
时,它会自动转换为FOO-NAME
。要获得它,您应该使用(intern "FOO-NAME")
。但是,如果需要,可以更改阅读器的默认行为(请参阅manual)。