2012-12-21 9 views
9

Es gibt etwas, das ich nicht über Common Lisp verstehen kann.Uninteressierte Symbole Symbole

Angenommen, ich bin ein Makro ähnlich wie diese zu schreiben:

(defmacro test-macro() 
    (let ((result (gensym))) 
     `(let ((,result 1)) 
     (print (incf ,result))))) 

als ich ich will jetzt

> (test-macro) 
2 
2 

tun können, um zu sehen, wie es

> (macroexpand-1 '(test-macro)) 
(LET ((#:G4315 1)) (PRINT (INCF #:G4315))) ; 
T 

Ok erweitert. Es gibt eindeutige Symbole, die mit gensym generiert wurden, die als unbenutzt gedruckt wurden.

Soweit ich weiß, sind die nicht durchbrochenen Symbole die Symbole, für die der Evaluator keine Symboldatenbindung intern erzeugt.

Also, wenn wir Makro zu dieser Form erweitern, sollte ein Fehler auf (inff #: G4315) sein. dies testen wir diese Form in der REPL nur auswerten können:

> (LET ((#:G4315 1)) (PRINT (INCF #:G4315))) 
*** - SETQ: variable #:G4315 has no value 

Warum also das Makro, das auf diese Zeichenfolge erweitert funktioniert perfekt und das Formular selbst nicht?

Antwort

16

Symbole können in einem Paket interniert werden oder nicht. Ein in einem Paket interniertes Symbol kann gesucht und gefunden werden. Ein nicht durchgebranntes Symbol kann nicht in einem Paket nachgeschlagen werden. Nur ein Symbol eines bestimmten Namens kann in einem Paket enthalten sein. Es gibt nur ein Symbol CL-USER::FRED.

Sie schreiben:

So soweit ich weiß, dass die uninterned Symbole sind Symbole, für die der Evaluator Bindung intern Symbol-Daten does erstellen.

Das ist falsch. Nicht eingeordnete Symbole sind Symbole, die in keinem Paket intern sind. Ansonsten sind sie vollkommen in Ordnung. intern bedeutet registriert in der Registrierung des Pakets für seine Symbole.

Der s-expression Leser das Namens Symbol verwenden und das Paket Symbole lesen während zu identifizieren. Wenn es kein solches Symbol gibt, wird es interniert. Wenn es einen gibt, wird dieser zurückgegeben.

Der Leser macht Symbole durch ihren Namen nachzuschlagen, hier im aktuellen Paket:

(read-from-string "FOO") -> symbol `FOO` 

ein zweites Mal: ​​

(read-from-string "FOO") -> symbol `FOO` 

es ist immer das gleiche Symbol FOO.

(eq (read-from-string "FOO") (read-from-string "FOO")) -> T 

#:FOO ist die Syntax für ein uninterned Symbol mit dem Namen FOO. Es ist in keinem Paket interniert. Wenn der Leser diese Syntax sieht, erstellt er ein neues Symbol ohne Unterbrechungen.

(read-from-string "#:FOO") -> new symbol `FOO` 

ein zweites Mal: ​​

(read-from-string "#:FOO") -> new symbol `FOO` 

beiden Symbole unterschiedlich sind. Sie haben den gleichen Namen, aber sie sind verschiedene Datenobjekte. Es gibt keine andere Registrierung für Symbole als die Pakete.

(eq (read-from-string "#:FOO") (read-from-string "#:FOO")) -> NIL 

So in Ihrem Fall (LET ((#:G4315 1)) (PRINT (INCF #:G4315))) sind die uninterned Symbole verschiedene Objekte. Der zweite ist dann eine andere Variable.

Common Lisp hat eine Möglichkeit, Daten zu drucken, so dass die Identität während des Druckens/Lese erhalten ist:

CL-USER 59 > (macroexpand-1 '(test-macro)) 
(LET ((#:G1996 1)) (PRINT (INCF #:G1996))) 
T 

CL-USER 60 > (setf *print-circle* t) 
T 

CL-USER 61 > (macroexpand-1 '(test-macro)) 
(LET ((#1=#:G1998 1)) (PRINT (INCF #1#))) 
T 

Jetzt sehen Sie, dass die gedruckte s-expression ein Etikett #1= für das erste Symbol hat . Es verweist dann später auf die gleiche Variable. Dies kann zurückgelesen werden und die Symbolidentitäten bleiben erhalten - obwohl das Lesegerät das Symbol nicht erkennen kann, wenn man das Paket ansieht.

So erstellt das Makro ein Formular, wo nur ein Symbol generiert wird. Wenn wir dieses Formular drucken und es zurücklesen wollen, müssen wir sicherstellen, dass die Identität der nicht-gebrauchten Symbole erhalten bleibt. Drucken mit *print-circle* festgelegt auf T hilft, das zu tun.

F: Warum wir uninterned erzeugten Symbole in Makros von GENSYM mit (Symbol erzeugen)?

Auf diese Weise können wir einzigartige neue Symbole haben, die nicht mit anderen Symbolen im Code kollidieren. Sie erhalten einen Namen von der Funktion gensym - in der Regel mit einer gezählten Nummer am Ende. Da es sich um frische neue Symbole handelt, die in keinem Paket enthalten sind, kann kein Namenskonflikt auftreten.

CL-USER 66 > (gensym) 
#:G1999 

CL-USER 67 > (gensym) 
#:G2000 

CL-USER 68 > (gensym "VAR") 
#:VAR2001 

CL-USER 69 > (gensym "PERSON") 
#:PERSON2002 

CL-USER 70 > (gensym) 
#:G2003 

CL-USER 71 > (describe *) 

#:G2003 is a SYMBOL 
NAME   "G2003" 
VALUE   #<unbound value> 
FUNCTION  #<unbound function> 
PLIST   NIL 
PACKAGE  NIL      <------- no package 
+1

Wenn ich Ihre Erklärung richtig verstanden hat, 'gensym' funktionieren würde nach wie vor richtig, auch wenn es nicht eine gezählte Anzahl auf den Namen des Symbols hinzugefügt hat, das heißt, wenn es ein uninterned Symbol mit dem gleichen Namen jedes Mal zurück es heißt (mit dem gleichen Argument). Ist das korrekt? Wenn ja: Warum fügt es die Nummer hinzu? Damit kann man leichter sagen, welche Symbole gleich sind und welche nicht in der Ausgabe von 'macro-expand' sind? – sepp2k

+4

@ sepp2k: Korrekt, die Nummer dient nur dazu, zu erkennen, wo nicht-unterteilte Symbole unterschiedlich sind und welche die gleichen sein können. Es ist eine Debugging-Hilfe. In früheren Lisp-Dialekten (ohne Pakete) hätte es wichtiger sein können. –

+0

Vielen Dank. Die * print-circle * Erklärung hilft wirklich zu verstehen, wie es funktioniert. Und danke für ein paar Erklärungen über nicht interpretierte Symbole. – JustAnotherCurious

0

gensym erzeugen Sie ein Symbol, und wenn Sie es drucken, erhalten Sie die "String" -Darstellung dieses Symbols, die nicht die gleiche Sache wie "Leser" -Darstellung ist, d. H. Die Codedarstellung des Symbols.