2012-12-21 16 views
9

Jest coś, czego nie mogę zrozumieć o typowym seplenieniu.Niezainicjowane symbole symboli

Załóżmy Piszę makro podobny do tego:

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

niż mogę zrobić

> (test-macro) 
2 
2 

Teraz chcę zobaczyć jak to rozszerza

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

Ok. Są unikalne symbole generowane z gensymem, które zostały wydrukowane jako niezamocowane.

O ile mi wiadomo, niezainicjowane symbole są symbolami, dla których oceniający nie tworzy wewnętrznie powiązania danych symboli.

Tak więc, jeśli makro-rozwinąć do tego formularza, powinien pojawić się błąd (np. # G4315). Aby to sprawdzić możemy tylko ocenić tę formę w REPL:

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

Więc dlaczego makro, które rozwija się do tego łańcucha działa idealnie, a sama forma nie?

Odpowiedz

16

Symbole mogą być internowane w pakiecie lub nie. Symbol internowany w pakiecie można wyszukać i znaleźć. Nieopisanego symbolu nie można znaleźć w paczce. Tylko jeden symbol pewnej nazwy może znajdować się w paczce. Jest tylko jeden symbol CL-USER::FRED.

Piszesz:

Więc o ile wiem, że uninterned symbole są symbolami, dla których oceniający does't tworzyć wiązania wewnątrz symbolu danych.

To źle. Niezainicjowane symbole są symbolami, które nie są internowane w żadnym opakowaniu pod numerem . W przeciwnym razie są idealnie w porządku. internowany oznacza zarejestrowany w rejestrze pakietu rejestru dla swoich symboli.

Identyfikator s 013185160993835102 s-expressionwykorzystuje nazwę symbolu i paczkę do identyfikacji symboli podczas czytania odczytu. Jeśli nie ma takiego symbolu, jest internowany. Jeśli istnieje, to ten jest zwracany.

Czytelnik nie patrzeć symbole ich imieniu, tutaj w obecnym pakiecie:

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

po raz drugi:

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

to jest zawsze taki sam symbol FOO.

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

#:FOO jest składnia dla uninterned symbol z nazwą FOO. Nie jest internowany w żadnym pakiecie. Jeśli czytelnik zobaczy tę składnię, tworzy nowy nieopisany symbol.

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

czas drugiego

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

Obydwa symbole są różne. Mają takie same nazwy, ale są to różne obiekty danych. Nie ma innego rejestru symboli, niż pakiety.

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

Zatem w przypadku (LET ((#:G4315 1)) (PRINT (INCF #:G4315))), że uninterned symbole są różne obiekty. Drugi to inna zmienna.

Common Lisp ma sposób, aby wydrukować dane, tak że tożsamość jest zachowana podczas drukowania/odczyt:

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 

Teraz widać, że drukowane s-wyrażenie ma etykietę #1= dla pierwszego symbolu . Następnie odwołuje się do tej samej zmiennej. To może być odczytywane z powrotem, a tożsamości symboli są zachowywane - nawet jeśli czytnik nie może zidentyfikować symbolu, patrząc na opakowanie.

W ten sposób makro tworzy formularz, w którym generowany jest tylko jeden symbol. Kiedy drukujemy ten formularz i chcemy go odczytywać, musimy upewnić się, że tożsamość niezainternowanych symboli została zachowana. Drukowanie z ustawieniem *print-circle* na T pomaga to zrobić.

Q: Dlaczego używamy uninterned wygenerowanych symboli makr za pomocą GENSYM (wygenerowania symbolu)?

W ten sposób możemy mieć unikalne nowe symbole, które nie kolidują z innymi symbolami w kodzie. Otrzymują nazwę przez funkcję gensym - zwykle z policzoną liczbą na końcu. Ponieważ są one świeżymi, nowymi symbolami, które nie są internowane w żadnym pakiecie, nie może być żadnego konfliktu nazw.

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

Gdybym zrozumiał swoje wyjaśnienie poprawnie, 'gensym' będzie nadal działać poprawnie, nawet jeśli nie liczy się ilość dodać do nazwy symbolu, czyli jeśli to zwrócił uninterned symbol o tej samej nazwie za każdym razem to się nazywa (z tym samym argumentem). Czy to jest poprawne? Jeśli tak, to dlaczego dodaje numer? Żeby łatwiej było stwierdzić, które symbole są takie same i które nie są na wyjściu 'makro-rozszerzenia'? – sepp2k

+4

@ sepp2k: poprawne, liczba jest po to, aby ułatwić wykrycie, gdzie symbole niezamieszkane są różne i które mogą być takie same. To jest pomoc do debugowania. We wcześniejszych dialektach Lispa (bez pakietów) mogło być ważniejsze. –

+0

Wielkie dzięki. Objaśnienie * print-circle * naprawdę pomaga zrozumieć, jak to działa. I dziękuję za wyjaśnienie również o niezamierzonych symbolach. – JustAnotherCurious

0

wygenerować symbol i podczas drukowania otrzymasz "ciąg" reprezentacji tego symbolu, który nie jest tym samym, co reprezentacja "czytnik", tj. Kod reprezentacji symbolu.