2016-06-23 3 views
1

Я пытаюсь написать следующий код, чтобы написать макрос, который, учитывая имя класса, автоматически создает класс с переменной экземпляра name и аксессуар для него в форме от classname-name.Создайте имя класса доступа из строки внутри макроса CL

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

+5

Do ответы [объединения двух переменных в одно имя функции in macro] (http://stackoverflow.com/questions/24433035/combining-two-variables-into-one-function-name-in-macro) решить это для вас? Обратите внимание, в частности, часть о формате в принятом ответе (отказ от ответственности: это мой). –

ответ

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

+0

Это сработало, спасибо. Тем не менее, мне интересно, почему в случае нормальной функции во втором случае он смог создать собственное имя. –

+1

@ sourav.d, причина в том, что вы используете символы для формирования нового имени (значения 'name1' и' name2'), поэтому они автоматически преобразуются в верхнем регистре читателем. – Renzo

+0

Вы также можете использовать '' ~: @ (~ A- ~ A ~) "для преобразования в верхний регистр, поскольку он использует формат в любом случае. – jkiiski

3

Обратите внимание, что класс уже имеет имя.

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

CL-USER 20 > (class-name *) 
FOO 
2

Не лучше ли это решение наследованием? Вот ваш Mixin:

(defclass named() 
    ((name :initarg :name :accessor name-of))) 

... и вы можете использовать его для всех других классов, которые определяют объекты, которые имеют название:

(defclass this (named) ...) 
(defclass that (named) ...) 
+0

Да, конечно, это лучший способ сделать это. Макрос был всего лишь экспериментом. –

Смежные вопросы