2008-09-25 8 views
89

Dopo aver attraversato le parti principali di un libro introduttivo Lisp, non riuscivo ancora a capire che cosa faccia la funzione dell'operatore speciale (quote) (o equivalente '), ma questo è tutto il codice Lisp che ho visto.Quando usare '(o quotare) in Lisp?

Cosa fa?

risposta

148

Risposta breve ignora le regole di valutazione di default e fare non valutare l'espressione (simbolo o s-exp), passando lungo la funzione esattamente come digitato.

lungo Risposta: La regola di valutazione di default

Quando un regolare (verrò a che più tardi) la funzione viene richiamata, tutti gli argomenti passati ad esso vengono valutati.Ciò significa che è possibile scrivere questo:

(* (+ a 2) 
    3) 

Che a sua volta valuta (+ a 2), valutando a e 2. Il valore del simbolo a viene cercato nel set vincolante variabile corrente, e poi sostituito. Dire a è attualmente legato al valore 3:

(let ((a 3)) 
    (* (+ a 2) 
    3)) 

ci saremmo (+ 3 2), + viene poi invocato il 3 e 2 cedendo 5. La nostra forma originale è ora (* 5 3) cedendo 15.

Spiegare quote Già!

OK. Come visto sopra, vengono valutati tutti gli argomenti di una funzione, quindi se si desidera passare il simbolo a e non il suo valore, non si desidera valutarlo. I simboli Lisp possono raddoppiare entrambi come valori e marcatori in cui in altre lingue sarebbero state utilizzate stringhe, come le chiavi per le tabelle hash.

Questo è il punto in cui entra quote. Si supponga di voler tracciare allocazioni di risorse da un'applicazione Python, ma piuttosto eseguire il tracciamento in Lisp. Avere il vostro Python app fare qualcosa di simile:

print "'(" 
while allocating: 
    if random.random() > 0.5: 
     print "(allocate %d)" random.randint(0, 20) 
    else: 
     print "(free %d)" % random.randint(0, 20) 
    ... 
print ")" 

Dare un output simile a questo (leggermente prettyfied):

'((allocate 3) 
    (allocate 7) 
    (free 14) 
    (allocate 19) 
    ...) 

ricordare ciò che ho detto su quote ("tick") che causa la regola di default non applicare? Buona. Quello che succederebbe altrimenti è che i valori di allocate e free vengono cercati, e non lo vogliamo. Nel nostro Lisp, desideriamo fare:

(dolist (entry allocation-log) 
    (case (first entry) 
    (allocate (plot-allocation (second entry))) 
    (free (plot-free (second entry))))) 

Per i dati di cui sopra, la seguente sequenza di chiamate di funzione sarebbe stato fatto:

(plot-allocation 3) 
(plot-allocation 7) 
(plot-free 14) 
(plot-allocation 19) 

ma che cosa circa list?

Bene, a volte si do si desidera valutare gli argomenti. Supponiamo che tu abbia una bella funzione che manipola un numero e una stringa e che restituisca un elenco delle cose ... risultanti. Facciamo una falsa partenza:

(defun mess-with (number string) 
    '(value-of-number (1+ number) something-with-string (length string))) 

Lisp> (mess-with 20 "foo") 
(VALUE-OF-NUMBER (1+ NUMBER) SOMETHING-WITH-STRING (LENGTH STRING)) 

Ehi! Non è quello che volevamo. Vogliamo in modo selettivo valutare alcuni argomenti e lasciare gli altri come simboli. Prova # 2!

(defun mess-with (number string) 
    (list 'value-of-number (1+ number) 'something-with-string (length string))) 

Lisp> (mess-with 20 "foo") 
(VALUE-OF-NUMBER 21 SOMETHING-WITH-STRING 3) 

Non Solo quote, ma backquote

Molto meglio! Incidentalmente, questo modello è così comune nelle macro (principalmente), che esiste una sintassi speciale per fare proprio questo.Il backquote:

(defun mess-with (number string) 
    `(value-of-number ,(1+ number) something-with-string ,(length string))) 

E 'come con quote, ma con la possibilità di valutare in modo esplicito alcuni argomenti da anteponendo virgola. Il risultato è equivalente all'utilizzo di list, ma se generi codice da una macro, spesso desideri solo valutare piccole parti del codice restituito, quindi il backquote è più adatto. Per gli elenchi più brevi, list può essere più leggibile.

Ehi, hai dimenticato quote!

Quindi, dove ci lascia? Oh, giusto, cosa fa effettivamente lo quote? Restituisce semplicemente il suo argomento (s) non valutato! Ricordi cosa ho detto all'inizio riguardo alle funzioni regolari? Risulta che alcuni operatori/funzioni hanno bisogno di non valutare i loro argomenti. Ad esempio IF - non vorresti che il ramo else venisse valutato se non fosse stato preso, giusto? I cosiddetti operatori , insieme a macro, funzionano così. Gli operatori speciali sono anche l '"assioma" del linguaggio - insieme minimo di regole - su cui è possibile implementare il resto del Lisp combinandoli in modi diversi.

Torna quote, però:

Lisp> (quote spiffy-symbol) 
SPIFFY-SYMBOL 

Lisp> 'spiffy-symbol ; ' is just a shorthand ("reader macro"), as shown above 
SPIFFY-SYMBOL 

confronta con gli (su Steel-Bank Common Lisp):

Lisp> spiffy-symbol 
debugger invoked on a UNBOUND-VARIABLE in thread #<THREAD "initial thread" RUNNING {A69F6A9}>: 
    The variable SPIFFY-SYMBOL is unbound. 

Type HELP for debugger help, or (SB-EXT:QUIT) to exit from SBCL. 

restarts (invokable by number or by possibly-abbreviated name): 
    0: [ABORT] Exit debugger, returning to top level. 

(SB-INT:SIMPLE-EVAL-IN-LEXENV SPIFFY-SYMBOL #<NULL-LEXENV>) 
0] 

perché non c'è spiffy-symbol nell'ambito corrente!

Sommando su

quote, backquote (con virgola), e list sono alcuni degli strumenti da utilizzare per creare elenchi, che non sono solo elenchi di valori, ma come hai visto possono essere utilizzati come leggero (non è necessario definire una struttura di dati struct)!

Se desideri saperne di più, ti consiglio il libro di Peter Seibel Practical Common Lisp per un approccio pratico all'apprendimento del Lisp, se sei già interessato alla programmazione in generale. Alla fine, durante il tuo viaggio in Lisp, inizierai a usare anche i pacchetti. Il The Idiot's Guide to Common Lisp Packages di Ron Garret ti darà una buona spiegazione di quelli.

Happy hacking!

48

Dice "non valutarmi". Ad esempio, se si desidera utilizzare un elenco come dati e non come codice, inserire una citazione in primo piano. Ad esempio,

(print '(+ 3 4)) stampe "(+ 3 4)", mentre (print (+ 3 4)) stampe "7"

+0

Come può essere valutato, ad esempio, esiste un comando 'unquote'? – William

+1

@William Lisps ha una comoda funzione chiamata 'eval':' (print (eval '(+ 3 4)) '. Questo è ciò che rende Lisps così eccezionale: le liste sono codice e il codice è liste, quindi un programma Lisp può manipolarsi da solo. – darkfeline

9

La citazione impedisce l'esecuzione o valutazione di un modulo, trasformandolo invece in dati. In generale è possibile eseguire i dati per poi evalualizzarli.

citazione crea strutture di dati della lista, ad esempio, i seguenti sono equivalenti:

(quote a) 
'a 

Può anche essere utilizzato per creare liste (o alberi):

(quote (1 2 3)) 
'(1 2 3) 

probabilmente stai meglio fuori ottenendo un libro introduttivo su lisp, come ad esempio Practical Common Lisp (che è disponibile per la lettura on-line).

11

Una risposta a questa domanda dice che QUOTE "crea strutture dati elenco". Questo non è giusto. QUOTE è più fondamentale di questo. In effetti, QUOTE è un operatore banale: il suo scopo è quello di impedire . In particolare, non crea nulla.

Cosa (QUOTE X) dice in pratica "non fare nulla, dammi solo X." X non deve essere una lista come in (QUOTE (A B C)) o un simbolo come in (QUOTE FOO). Può essere qualsiasi oggetto qualunque. In effetti, il risultato della valutazione della lista prodotta da (LISTA 'QUOTE SOME-OBJECT) restituirà sempre SOME-OBJECT, qualunque esso sia.

Ora, la ragione per cui (QUOTE (A B C)) sembra come se avesse creato una lista i cui elementi sono A, B e C è che tale lista è davvero ciò che restituisce; ma al momento in cui viene valutato il modulo QUOTE, l'elenco è già in uso da un po '(come componente del modulo QUOTE!), creato dal caricatore o dal lettore prima dell'esecuzione del codice.

Una delle implicazioni di ciò che tende a far inciampare i neofiti abbastanza spesso è che è molto imprudente modificare un elenco restituito da un modulo QUOTE. I dati restituiti da QUOTE sono, a tutti gli effetti, considerati come parte del codice in esecuzione e devono quindi essere considerati come di sola lettura!

13

Altre persone hanno risposto a questa domanda in modo ammirevole, e Matthias Benkard porta un avvertimento eccellente.

NON UTILIZZARE IL PREVENTIVO PER CREARE ELENCHI CHE SARANNO SUCCESSIVAMENTE MODIFICATI. La specifica consente al compilatore di trattare le liste citate come costanti. Spesso, un compilatore ottimizzerà le costanti creando un singolo valore per loro in memoria e quindi facendo riferimento a quel singolo valore da tutte le posizioni in cui appare la costante. In altre parole, può trattare la costante come una variabile globale anonima.

Ciò può causare problemi evidenti. Se modifichi una costante, potrebbe benissimo modificare altri usi della stessa costante in codice completamente non correlato. Ad esempio, puoi confrontare alcune variabili a '(1 1) in alcune funzioni, e in una funzione completamente diversa, inizia una lista con' (1 1) e poi aggiungi più cose ad essa. Eseguendo queste funzioni, potresti scoprire che la prima funzione non corrisponde più correttamente alle cose, perché ora sta cercando di confrontare la variabile con '(1 1 2 3 5 8 13), che è ciò che la seconda funzione ha restituito.Queste due funzioni sono completamente non correlate, ma hanno un effetto l'una sull'altra a causa dell'uso delle costanti. Possono verificarsi anche effetti negativi più pazzeschi, come un'iterazione della lista perfettamente normale che improvvisamente si trasforma in loop infinito.

Utilizzare preventivo quando è necessario un elenco costante, ad esempio per il confronto. Usa l'elenco quando modifichi il risultato.

+0

Quindi sembra che dovresti usare '(list (+ 1 2))' il più delle volte. In tal caso, come si impedisce la valutazione di '(+ 1 2)' all'interno di un simile esempio? Esiste un comando 'unquote'? – William

+0

Vuoi l'equivalente di ''((3))', o l'equivalente di '' ((+ 1 2))'? Se quest'ultimo, devi usare più 'list':' (lista (lista '+ 1 2)) '. O se volevi l'equivalente di ''(+ 1 2)', solo '(lista' + 1 2)'. E ricorda, se non stai modificando la lista, sentiti libero di usare la citazione: non c'è niente di sbagliato in ''(+ 1 2)' se stai solo confrontandoti con essa o qualcosa del genere. – Xanthir

+0

Ti piace referenziare dove le liste citate dovrebbero essere trattate come costanti? – William

2

Quando vogliamo passare un argomento stesso anziché passare il valore dell'argomento, allora usiamo la citazione. È principalmente correlato alla procedura che passa durante l'utilizzo di elenchi, coppie e atomi che non sono disponibili nel linguaggio di programmazione C (la maggior parte delle persone inizia a programmare utilizzando la programmazione C, quindi ci confondono) Questo è il codice in linguaggio di programmazione Scheme che è un dialetto di lisp e immagino che tu possa capire questo codice.

(define atom?    ; defining a procedure atom? 
    (lambda (x)    ; which as one argument x 
(and (not (null? x)) (not(pair? x))))) ; checks if the argument is atom or not 
(atom? '(a b c)) ; since it is a list it is false #f 

L'ultima riga (atomo? 'Abc) passa abc in quanto è la procedura per verificare se ABC è un atomo o no, ma quando si passa (atomo? Abc) allora controlla per il valore di ABC e passa il valore ad esso. Dal momento che non ne abbiamo fornito alcun valore

0

Quote restituisce la rappresentazione interna dei suoi argomenti. Dopo aver arato troppe spiegazioni su ciò che la citazione non fa, è quando la lampadina si accende. Se il REPL non ha convertito i nomi delle funzioni in UPPER-CASE quando li ho citati, potrebbe non essermi reso conto.

Così. Le funzioni Lisp ordinarie convertono i loro argomenti in una rappresentazione interna, valutano gli argomenti e applicano la funzione. Quote converte i suoi argomenti in una rappresentazione interna e restituisce semplicemente ciò. Tecnicamente è corretto dire che la citazione dice "non valutare", ma quando stavo cercando di capire cosa ha fatto, dirmi cosa non è stato frustrante. Il mio tostapane non valuta neanche le funzioni Lisp; ma non è così che spieghi cosa fa un tostapane.

0

Anoter risposta breve:

quote significa senza valutare, e backquote è citazione, ma lasciare porte posteriori.

Un buon referrence:

Emacs Lisp Manuale di riferimento che sia molto chiaro

9.3 Citando

La forma citazione speciale restituisce il suo unico argomento, come scritto, senza valutare esso. Questo fornisce un modo per includere simboli e liste costanti, che non sono oggetti auto-valutanti, in un programma. (Non è necessario citare gli oggetti di auto-valutazione, come numeri, stringhe e vettori.)

forma speciale: citazione opporsi

This special form returns object, without evaluating it. 

Perché citazione è utilizzato così spesso nei programmi, Lisp fornisce una vantaggiosa leggi la sintassi per questo. Un carattere apostrofo ('' ') seguito da un oggetto Lisp (in sintassi di lettura) si espande in una lista il cui primo elemento è quote e il cui secondo elemento è l'oggetto. Pertanto, la sintassi di lettura 'x è un'abbreviazione per (citazione x).

Ecco alcuni esempi di espressioni che utilizzano citazione:

(quote (+ 1 2)) 
    ⇒ (+ 1 2) 

(quote foo) 
    ⇒ foo 

'foo 
    ⇒ foo 

''foo 
    ⇒ (quote foo) 

'(quote foo) 
    ⇒ (quote foo) 

9.4 backquote

backquote costrutti consentono di citare una lista, ma in modo selettivo valutare gli elementi di tale elenco. Nel caso più semplice, è identico alla citazione della forma speciale (descritta nella sezione precedente, vedi Quoting). Ad esempio, queste due forme producono risultati identici:

`(a list of (+ 2 3) elements) 
    ⇒ (a list of (+ 2 3) elements) 

'(a list of (+ 2 3) elements) 
    ⇒ (a list of (+ 2 3) elements) 

Il marcatore speciale ‘’ all'interno dell'argomento backquote indica un valore che non è costante. Il valutatore Emacs Lisp valuta l'argomento del ‘’, e mette il valore nella struttura della lista:

`(a list of ,(+ 2 3) elements) 
    ⇒ (a list of 5 elements) 

Sostituzione con ‘’ è consentito a livelli più profondi della struttura della lista anche. Per esempio:

`(1 2 (3 ,(+ 4 5))) 
    ⇒ (1 2 (3 9)) 

È possibile anche unire un valore valutato nella lista risultante, utilizzando il marcatore speciale ‘@’. Gli elementi dell'elenco splicito diventano elementi allo stesso livello degli altri elementi dell'elenco risultante. Il codice equivalente senza usare `` 'è spesso illeggibile. Ecco alcuni esempi:

(setq some-list '(2 3)) 
    ⇒ (2 3) 

(cons 1 (append some-list '(4) some-list)) 
    ⇒ (1 2 3 4 2 3) 

`(1 ,@some-list 4 ,@some-list) 
    ⇒ (1 2 3 4 2 3) 
1

in Emacs Lisp:

Cosa può essere citato?

Elenchi e simboli.

La quotazione di un numero restituisce il numero stesso: '5 corrisponde a 5.

Cosa succede quando si citano le liste?

Ad esempio:

'(one two) viene valutato come

(list 'one 'two) che restituisce

(list (intern "one") (intern ("two"))).

(intern "one") crea un simbolo denominato "uno" e lo memorizza in un hash-map "centrale", quindi ogni volta che si dicono 'one poi il simbolo denominato "one" sarà guardato in quel hash-map centrale.

Ma che cos'è un simbolo?

Per esempio, in OO-lingue (Java/Javascript/Python) un simbolo potrebbe essere rappresentato come un oggetto che ha un campo name, che è il nome del simbolo come "one" sopra, e dati e/o codice può essere associato ad esso questo oggetto.

Quindi, un simbolo in Python potrebbe essere implementata come:

class Symbol: 
    def __init__(self,name,code,value): 
     self.name=name 
     self.code=code 
     self.value=value 

In Emacs Lisp per esempio, un simbolo può avere 1) i dati ad esso associato e (al tempo stesso - per lo stesso simbolo) 2) codice associato ad esso - a seconda del contesto, vengono richiamati i dati o il codice.

Per esempio, in Elisp:

(progn 
    (fset 'add '+) 
    (set 'add 2) 
    (add add add) 
) 

viene valutato come 4.

Perché (add add add) valuta come:

(add add add) 
(+ add add) 
(+ 2 add) 
(+ 2 2) 
4 

Così, ad esempio, utilizzando la classe Symbol abbiamo definito in Python sopra, questo add ELisp simbolo potrebbe essere scritto in Python come Symbol("add",(lambda x,y: x+y),2).

Grazie mille per la gente su IRC#emacs per spiegare simboli e citazioni a me.

Problemi correlati