2010-12-27 9 views
10

Zastanawiam się nad celem, a może bardziej poprawnie, zadaniami "czytnika" podczas interpretacji/kompilacji programów Lisp.Jakie są zadania "czytnika" podczas interpretacji Lispa?

Z badań wstępnych, które właśnie przeprowadziłem, wydaje mi się, że czytelnik (szczególnie w tym przypadku Clojure) może być uważany za "syntaktyczny preprocesor". Jego główne obowiązki to ekspansja makr czytników i form prymitywnych. Tak więc, dwa przykłady:

'cheese   --> (quote cheese) 
{"a" 1 "b" 2} --> (array-map "a" 1 "b" 2) 

więc czytnik wykonuje w tekście programu (składającej się z S-ekspresji), a następnie buduje i zwraca się w pamięci danych, strukturę, którą można wyznaczyć bezpośrednio.

Jak daleko od prawdy jest to (i czy nadmiernie uprościłem cały proces)? Jakie inne zadania wykonuje czytelnik? Biorąc pod uwagę cnotę Lispsa to ich homoikoniczność (kod jako dane), dlaczego istnieje potrzeba analizy leksykalnej (jeśli rzeczywiście jest to porównywalne z zadaniem czytelnika)?

Dzięki!

Odpowiedz

20

Ogólnie czytnik w Lisp czyta wyrazy s i zwraca struktury danych. READ to operacja we/wy: Input to strumień znaków, a dane wyjściowe to dane Lisp.

Drukarka działa odwrotnie: pobiera dane Lisp i wysyła je jako strumień znaków. W ten sposób może również drukować dane Lisp do zewnętrznych wyrażeń s.

Należy pamiętać, że interpretacja oznacza coś konkretnego: wykonanie kodu przez tłumacza. Ale wiele systemów Lisp (w tym Clojure) używa kompilatora. Zadania obliczania wartości dla formularza Lisp są zwykle nazywane oszacowaniem. Ewaluacja może być realizowana poprzez interpretację, kompilację lub połączenie obu.

S-Expression: wyrażenia symboliczne. Zewnętrzna, tekstowa reprezentacja danych. Zewnętrzne oznacza, że ​​s-wyrażenia są tym, co widzisz w plikach tekstowych, łańcuchach itp. Tak więc wyrażenia s są tworzone z postaci na niektórych, zazwyczaj zewnętrznych, środkach.

Lisp struktury danych: symbole, listy, łańcuchów, liczb, znaków, ...

Reader: czyta s-wyrażeń i zwraca Lisp struktur danych.

Należy zauważyć, że wyrażeń s również służą do kodowania kodu źródłowego Lisp.

W niektórych dialektach Lisp czytnik jest programowalny i sterowany tabelą (za pomocą tak zwanej tabeli odczytu). Ta tabela czytająca zawiera funkcje czytnika dla postaci. Na przykład cudzysłów "znak jest związany z funkcją, która odczytuje wyrażenie i zwraca wartość (lista" wyrażenie cytowania). Znaki liczbowe 0..9 są powiązane z funkcjami, które odczytują liczbę (w rzeczywistości może to być bardziej złożone, ponieważ niektóre Lisps umożliwiają odczyt liczb w różnych bazach).

Wyrażenia S zapewniają zewnętrzną składnię struktur danych.

Programy Lisp są napisane w formie zewnętrznej za pomocą wyrażeń s.Ale nie wszystkie wyrażenia s są poprawnymi programami Lisp:

(if a b c d e) is usually not a valid Lisp program 

Składnia Lispa jest zwykle określana na podstawie danych Lisp.

IF ma na przykład następującą składnię (w Common Lisp http://www.lispworks.com/documentation/HyperSpec/Body/s_if.htm):

if test-form then-form [else-form] 

więc spodziewa się test-formularz, a następnie-formę i opcjonalnego innego formularza.

jako S-wyrażenia Poniżej znajdują się ważne, jeżeli wyrażenia:

(if (foo) 1 2) 
(if (bar) (foo)) 

Ale ponieważ programy Lisp to formy, możemy również zbudować te formy za pomocą Lisp programy:

(lista 'if' (foo) 1 2) jest programem Lisp, który zwraca poprawny formularz IF.

CL-USER 24 > (describe (list 'if '(foo) 1 2)) 

(IF (FOO) 1 2) is a LIST 
0  IF 
1  (FOO) 
2  1 
3  2 

Ta lista może na przykład zostać wykonana z EVAL. EVAL oczekuje formularzy listy - nie wyrażeń s. Pamiętaj, że wyrazy s to tylko zewnętrzna reprezentacja. Aby utworzyć formularz Lisp, musimy CZYTAĆ go.

To dlatego mówi się, że kod to dane. Formy Lispa są wyrażane jako wewnętrzne struktury danych Lispa: listy, symbole, liczby, łańcuchy, ... W większości innych języków programowania kod jest tekstem nieprzetworzonym. W wyrażeniach s Lisp są nieprzetworzone teksty. Po odczytaniu funkcją READ wyrażenia s są przekształcane w dane.

W ten sposób podstawowa interakcja na najwyższym poziomie w Lisp nazywa się REPL, Read Eval Print Loop. Jest pętlę, która wielokrotnie odczytuje S-wyrażenie, ocenia Lisp formę i drukuje go:

READ : s-expression -> lisp data 
EVAL : lisp form -> resulting lisp data 
PRINT: lisp data -> s-expression 

Więc najbardziej prymitywny REPL jest:

(loop (print (eval (read)))) 

Zatem z koncepcyjnego punktu widzenia, aby odpowiedzieć na twoje pytanie, podczas oceny czytelnik nic nie robi. Nie bierze udziału w ocenie. Ocena odbywa się za pomocą funkcji EVAL. Czytnik jest wywoływany przez wywołanie READ. Ponieważ EVAL używa struktur danych Lisp jako danych wejściowych (a nie s-wyrażeń), czytnik jest uruchamiany przed oceną formy Lisp (na przykład poprzez interpretację lub kompilację i wykonanie).

+3

Dzięki za miłe wyjaśnienie. Można więc powiedzieć, że czytnik odczytuje w danych programu jako zwykły tekst o strukturze S-wyrażeń i zwraca strukturę danych Lisp. Nie ocenia żadnego z tych wyrażeń, ale po prostu przedstawia je w pamięci w sposób, który można skutecznie ocenić? Widzę teraz wyraźniej różnicę między oceniającym (zgodnie z rozdziałem SICP "Metacircular Abstraction", w którym prezentowany jest prosty ewaluator Lisp-in-LISP) i pełnoprawnym tłumaczem. – Andrew

+4

@Andrew: w prawo. Generalnie czytelnik nie ocenia rzeczy. Po prostu tworzy struktury danych Lisp dla s-wyrażenia. Teraz oceniający może zinterpretować te wewnętrzne struktury danych - faza leksykalna jest już wykonana. Często programy te, jako dane, są kompilowane do kodu maszynowego lub bajtowego w kroku pośrednim. Zauważ także, że na przykład czytnik Common Lisp ma możliwość oceny rzeczy. '(1 2 #. (+ 1 2)) zwraca (1 2 3). #. to makro czytnika, które ocenia następne wyrażenie w czasie odczytu. Można również zaimplementować dodatkowe zachowanie poprzez tabele odczytu. –