Macros 从CL宏中的字符串创建类访问器名称

Macros 从CL宏中的字符串创建类访问器名称,macros,lisp,common-lisp,symbols,Macros,Lisp,Common Lisp,Symbols,我尝试用下面的代码编写一个宏,给定一个类的名称,该宏会自动创建一个带有name实例变量的类,并以classname的形式为其创建一个访问器 (defmacro def-named-class (class-name) `(defclass ,class-name () ((name :accessor ,(intern (format nil "~A-~A" class-name "name")) :initarg :name :initf

我尝试用下面的代码编写一个宏,给定一个类的名称,该宏会自动创建一个带有
name
实例变量的类,并以
classname
的形式为其创建一个访问器

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

您应该将名称转换为大写:

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

原因是公共Lisp读取器的默认行为是在读取任何大写符号时对其进行转换。因此,当您编写
foo-name
时,它会自动转换为
foo-name
。要获得它,您应该使用
(intern“FOO-NAME”)
。但是,如果需要,您可以更改读卡器的默认行为(请参阅)。

您应该将名称转换为大写:

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

原因是公共Lisp读取器的默认行为是在读取任何大写符号时对其进行转换。因此,当您编写
foo-name
时,它会自动转换为
foo-name
。要获得它,您应该使用
(intern“FOO-NAME”)
。但是,如果需要,可以更改读取器的默认行为(请参见)。

注意,类已经有了名称

CL-USER 19 > (defclass foo () ())
#<STANDARD-CLASS FOO 415040BE6B>

CL-USER 20 > (class-name *)
FOO
CL-USER 19>(defclass foo())
#
CL-USER 20>(类名*)
福

请注意,类已经有了名称

CL-USER 19 > (defclass foo () ())
#<STANDARD-CLASS FOO 415040BE6B>

CL-USER 20 > (class-name *)
FOO
CL-USER 19>(defclass foo())
#
CL-USER 20>(类名*)
福

继承不是更好的解决方法吗?这是你的混音:

(defclass named ()
  ((name :initarg :name :accessor name-of)))
。。。您可以将其用于定义具有名称的对象的所有其他类:

(defclass this (named) ...)
(defclass that (named) ...)

继承不是更好的解决方法吗?这是你的混音:

(defclass named ()
  ((name :initarg :name :accessor name-of)))
。。。您可以将其用于定义具有名称的对象的所有其他类:

(defclass this (named) ...)
(defclass that (named) ...)

这很有效,谢谢。但是,我想知道为什么在第二种情况下,普通函数能够创建正确的名称。@sourav.d,原因是您使用符号来形成新名称(名称1和名称2的值),因此读取器会自动将它们转换为大写。您也可以使用
“~:@(~a-~a~)
转换为大写,因为它仍然使用格式。转换为大写是不够的,可能与盲目使用小写名称一样错误。如果类或插槽名称应该包含小写字母,会发生什么情况?这已经在中讨论过了(请参见不要(天真地)在我的答案中使用格式创建符号名称)。一个合适的解决方案需要在符号名称中保留大小写,而不是更改它们,并且需要记录将添加什么作为后缀。这很有效,谢谢。但是,我想知道为什么在第二种情况下,普通函数能够创建正确的名称。@sourav.d,原因是您使用符号来形成新名称(名称1和名称2的值),因此读取器会自动将它们转换为大写。您也可以使用
“~:@(~a-~a~)
转换为大写,因为它仍然使用格式。转换为大写是不够的,可能与盲目使用小写名称一样错误。如果类或插槽名称应该包含小写字母,会发生什么情况?这已经在中讨论过了(请参见不要(天真地)在我的答案中使用格式创建符号名称)。正确的解决方案需要保留符号名称中的大小写,而不是更改它们,并且需要记录将添加哪些内容作为后缀。您是否知道如何解决此问题?请特别注意已接受答案中关于格式的部分(免责声明:这是我的)。这些答案能帮你解决这个问题吗?请特别注意接受答案中关于格式的部分(免责声明:这是我的)。是的,当然这是更好的方法。宏只是一个实验。是的,当然这是更好的方法。宏只是一个实验。