2010-12-27 8 views
10

Mi chiedo quale sia lo scopo, o forse più correttamente, dei compiti del "lettore" durante l'interpretazione/compilazione dei programmi Lisp.Quali sono i compiti del "lettore" durante l'interpretazione del Lisp?

Dalla ricerca pre-interrogativa che ho appena svolto, mi sembra che un lettore (in particolare in questo caso Clojure) possa essere pensato come un "preprocessore sintattico". I suoi compiti principali sono l'espansione delle macro dei lettori e le forme primitive. Quindi, due esempi:

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

così il lettore prende nel testo di un programma (che consiste di S-espressioni) e poi costruisce e restituisce un in memoria dati-struttura che può essere valutata direttamente.

Quanto lontano dalla verità è questa (e ho semplificato eccessivamente l'intero processo)? Quali altri compiti svolge il lettore? Considerando una virtù di Lisps è la loro omoiconicità (codice come dati), perché c'è bisogno di un'analisi lessicale (se tale è effettivamente paragonabile al lavoro del lettore)?

Grazie!

risposta

20

Generalmente il lettore in Lisp legge espressioni s e restituisce strutture dati. READ è un'operazione di I/O: Input è un flusso di caratteri e l'output è dati Lisp.

La stampante fa il contrario: prende i dati Lisp e li emette come un flusso di caratteri. In questo modo può anche stampare dati Lisp su espressioni S esterne.

Nota che l'interpretazione indica qualcosa di specifico: esecuzione di codice da parte di un interprete. Ma molti sistemi Lisp (incluso Clojure) stanno usando un compilatore. Il compito di calcolare un valore per un modulo Lisp è solitamente chiamato valutazione. La valutazione può essere implementata attraverso l'interpretazione, la compilazione o un mix di entrambi.

S-Expression: espressioni simboliche. Rappresentazione esterna e testuale dei dati. Esterno significa che le espressioni S sono ciò che vedete nei file di testo, nelle stringhe, ecc. Quindi le espressioni s sono fatte di caratteri su alcuni media, tipicamente esterni.

strutture dati Lisp: simboli, liste, stringhe, numeri, caratteri, ...

Reader: legge s-espressioni e restituisce strutture dati Lisp.

Si noti che le espressioni s vengono anche utilizzate per codificare il codice sorgente Lisp.

In alcuni dialoghi Lisp il lettore è programmabile e guidato da una tabella (tramite la cosiddetta tabella di lettura). Questa tabella di lettura contiene funzioni di lettura per i caratteri. Ad esempio, il carattere 'citazione' è associato a una funzione che legge un'espressione e restituisce il valore di (elenco 'espressione espressione). I caratteri numerici 0..9 sono associati a funzioni che leggono un numero (in realtà potrebbe essere più complesso, dal momento che alcuni Lisp consentono di leggere i numeri in basi diverse).

Le espressioni S forniscono la sintassi esterna per le strutture di dati.

I programmi Lisp sono scritti in forma esterna tramite le espressioni s.Ma non tutti i s-espressioni sono validi programmi Lisp:

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

la sintassi di Lisp di solito è definito sulla parte superiore dei dati Lisp.

IF ha ad esempio la seguente sintassi (in Common Lisp http://www.lispworks.com/documentation/HyperSpec/Body/s_if.htm):

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

Quindi aspetta un test-form, un allora forma e un altro in forma opzionale.

S-espressioni seguenti sono valide se le espressioni:

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

Ma dal momento che i programmi Lisp sono forme, possiamo anche costruire queste forme utilizzando programmi Lisp:

(lista 'se' (foo) 1 2) è un programma Lisp che restituisce un modulo IF valido.

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

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

Questo elenco può essere eseguito ad esempio con EVAL. EVAL si aspetta moduli di elenco - non s-espressioni. Ricorda che le espressioni s sono solo una rappresentazione esterna. Per creare un modulo Lisp, dobbiamo leggerlo.

Questo è il motivo per cui si dice che il codice è. I moduli Lisp sono espressi come strutture dati Lisp interne: liste, simboli, numeri, stringhe, .... Nella maggior parte degli altri linguaggi di programmazione il codice è testo non elaborato. In Lisp le espressioni s sono testo non elaborato. Se letti con la funzione READ, le espressioni s vengono trasformate in dati.

Quindi l'interazione di base di livello superiore in Lisp è denominata REPL, Read Eval Print Loop. E 'un ciclo che legge ripetutamente una s-espressione, valuta la forma Lisp e lo stampa:

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

Così il più primitivo REPL è:

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

Così, da un punto di vista concettuale, per rispondere alla tua domanda, durante la valutazione il lettore non fa nulla. Non è coinvolto nella valutazione. La valutazione viene eseguita dalla funzione EVAL. Il lettore è invocato da una chiamata a READ. Poiché EVAL utilizza le strutture dati Lisp come input (e non come espressioni S), il lettore viene eseguito prima che il modulo Lisp venga valutato (ad esempio mediante interpretazione o compilandolo ed eseguendolo).

+3

Grazie per il bel chiarimento. Quindi, si potrebbe dire che il lettore legge i dati del programma come testo semplice strutturato come S-espressioni e restituisce una struttura di dati Lisp. Non valuta nessuna di quelle espressioni, ma semplicemente le rappresenta in memoria in un modo che può essere valutato in modo efficace? Ora sto vedendo più chiaramente la differenza tra un valutatore (come nel capitolo "astrazione metacircolare" di SICP in cui è presentato un semplice valutatore lisp-in-lisp) e un interprete a tutti gli effetti. – Andrew

+4

@Andrew: giusto. Generalmente il lettore non valuta le cose. Crea solo una struttura dati Lisp per l'espressione s. Ora un valutatore potrebbe interpretare questi datastrutture interne - la fase del lexer è già stata eseguita. Spesso questi programmi come dati vengono compilati su un codice macchina o byte in una fase intermedia. Si noti inoltre che, ad esempio, il lettore Common Lisp ha la possibilità di valutare le cose. '(1 2 #. (+ 1 2)) restituisce (1 2 3). #. è una macro del lettore che valuta l'espressione successiva al momento della lettura. Si può anche implementare un comportamento aggiuntivo tramite le tabelle di lettura. –