2016-06-23 33 views
1

Ich versuche den folgenden Code, um einen Makro zu schreiben, der eine Klasse mit einer name Instanzvariable und einem Accessor für das Formular automatisch erstellt von classname-name.Erstellen Sie einen Klassenaccessornamen aus einem String in einem CL-Makro

(defmacro def-named-class (class-name) 
    `(defclass ,class-name() 
    ((name :accessor ,(intern (format nil "~A-~A" class-name "name")) 
      :initarg :name 
      :initform "")))) 

Das Problem hier ist, dass, wenn das Makro ausgeführt wird, etwa mit einem Argument foo, der Name der Accessorfunktion als |FOO-name| kommt, aber ich würde es nur foo-name sein wollen. Der Grund ist, (intern "foo-name") gibt ein Symbol |foo-name| zurück. Allerdings, wenn ich versuchen, das gleiche mit einer normalen Funktion zu tun, wie folgt aus:

(defmacro def-hyp (name1 name2 arg-list &body body) 
    `(defun ,(intern (format nil "~A-~A" name1 name2)) 
      ,arg-list 
      ,@body)) 

Und es dann nennen wie (def-hyp foo name() 'foo-name) es produziert richtig eine Funktion mit dem Namen foo-name. Ich frage mich also, ob es eine Methode gibt, um genau das gleiche Symbol aus der Zeichenfolgendarstellung im ersten Makro zu erhalten. Ich benutze Clozure CL.

+5

Sie die Antworten auf [die Kombination von zwei Variablen in einem Funktionsnamen im Makro] (http://stackoverflow.com/questions/24433035/combining-two-variables-into-one-function-name-in-macro) lösen dies für Sie? Beachten Sie besonders den Teil über das Format in der akzeptierten Antwort (Disclaimer: es gehört mir). –

Antwort

1

Sie sollten die Namen in Großbuchstaben umwandeln:

(defmacro def-named-class (class-name) 
    `(defclass ,class-name() 
    ((name :accessor ,(intern (format nil "~A-~A" (string-upcase class-name) "NAME")) 
      :initarg :name 
      :initform "")))) 

Ein andere Möglichkeit ist, wie in einem Kommentar von jkiiski vorgeschlagen, nur das Format-String zu ändern:

... 
((name :accessor ,(intern (format nil "~:@(~A-~A~)" class-name "name")) 
... 

Der Grund dafür ist, dass Das Standardverhalten des Common-Lisp-Readers besteht darin, jedes Symbol beim Lesen in Großbuchstaben umzuwandeln. Wenn Sie also foo-name schreiben, wird es automatisch in FOO-NAME umgewandelt. Um es zu erhalten, sollten Sie (intern "FOO-NAME") verwenden. Wenn Sie möchten, können Sie jedoch das Standardverhalten des Lesers ändern (siehe manual).

+0

Das hat funktioniert, danke. Ich frage mich jedoch, warum es im Falle einer normalen Funktion im zweiten Fall möglich war, den richtigen Namen zu erstellen. –

+1

@ sourav.d, der Grund ist, dass Sie Symbole verwenden, um den neuen Namen zu bilden (die Werte von 'name1' und' name2'), so dass sie vom Leser automatisch in Großbuchstaben konvertiert werden. – Renzo

+0

Sie könnten auch '" ~: @ (~ A- ~ A ~) "' verwenden, um in upcase umzuwandeln, da das Format sowieso verwendet wird. – jkiiski

3

Beachten Sie, dass eine Klasse bereits einen Namen hat.

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

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

Ist es nicht besser durch Vererbung gelöst? Hier ist Ihre mixin:

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

... und Sie können es für alle anderen Klassen verwenden, die Objekte definieren, die einen Namen haben:

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

Ja, natürlich ist das der bessere Weg. Das Makro war nur ein Experiment. –