Un simbolo che si trova in una posizione non funzionale viene trattato come il nome di una variabile. In (function variable) functionè in posizione di funzione (dopo la parentesi aperta) e variablenon lo è. A meno che le variabili espressamente citate non vengano sostituite con i loro valori.
Se dovessi scrivere (boundp my-variable)ciò significherebbe che "è il simbolo memorizzato nel valore di variabile my-variableassociato come variabile" e non "è il simbolo my-variableassociato come variabile.
Quindi perché si bound-and-truepcomporta diversamente?
Questa è una macro e le normali regole di valutazione (funzione) non si applicano qui, le macro sono libere di decidere se e quando vengono valutati i loro argomenti. Ciò che effettivamente fanno le macro è in qualche modo trasformare gli argomenti e restituire il risultato come un elenco, che viene quindi valutato. La trasformazione e la valutazione finale avvengono in momenti diversi, chiamati tempo di macro-espansione e tempo di valutazione.
Ecco bound-and-true-pcome appare la definizione di :
(defmacro bound-and-true-p (var)
"Return the value of symbol VAR if it is bound, else nil."
`(and (boundp (quote ,var)) ,var))
Questo utilizza macro lettore che sono diverse dalle macro lisp (più su quello sotto). Per non complicare ulteriormente ciò, non utilizzare macro di lettori:
(defmacro bound-and-true-p (var)
"Return the value of symbol VAR if it is bound, else nil."
(list 'and (list 'boundp (list 'quote var)) var))
Se scrivi
(bound-and-true-p my-variable)
che viene prima "tradotto" in
(and (boundp 'my-variable) my-variable)
e quindi quello viene valutato restituendo nilse my-variablenon lo è boundpoppure il valore di my-variable(che ovviamente può anche essere nil).
Potresti aver notato che l'espansione non lo era
(and (boundp (quote my-variable)) my-variable)
come ci saremmo aspettati. quoteè una forma speciale, non una macro o una funzione. Come le macro, le forme speciali possono fare qualsiasi cosa con i loro argomenti. Questa particolare forma speciale restituisce semplicemente il suo argomento, qui un simbolo, anziché il valore variabile del simbolo. Questo è in realtà l'unico scopo di questa forma speciale: impedire la valutazione! Le macro non possono farlo da sole, devono usare quoteper farlo.
Allora, che succede '? È una macro del lettore , che come detto sopra non è la stessa di una macro lisp . Mentre le macro vengono utilizzate per trasformare codice / dati, le macro del lettore vengono utilizzate in precedenza durante la lettura del testo per trasformarlo in codice / dati.
'something
è una forma abbreviata di
(quote something)
`utilizzato nella definizione effettiva di bound-and-true-panche è una macro del lettore. Se cita un simbolo come in `symbolesso equivale a 'symbol, ma quando viene utilizzato per citare un elenco come in `(foo bar ,baz)esso si comporta in modo diverso in quanto ,vengono valutati i moduli con prefisso .
`(constant ,variable)
è equivalente a
(list (quote constant) variable))
Questo dovrebbe rispondere alla domanda sul perché a volte i simboli non quotati vengono valutati (sostituiti con i loro valori) e talvolta no; le macro possono essere utilizzate quoteper impedire la valutazione di un simbolo.
Ma perché bound-and-true-puna macro boundpnon lo è? Dobbiamo essere in grado di determinare se simboli arbitrari, che non sono noti fino al runtime, sono associati come simboli. Ciò non sarebbe possibile se l' boundpargomento fosse automaticamente citato.
bound-and-true-pviene utilizzato per determinare se è definita una variabile nota e in tal caso utilizzare il suo valore. Ciò è utile se una libreria ha una dipendenza opzionale da una libreria di terze parti come in:
(defun foo-get-value ()
(or (bound-and-true-p bar-value)
;; we have to calculate the value ourselves
(our own inefficient or otherwise undesirable variant)))
bound-and-true-ppotrebbe essere definito come una funzione e richiedere che l'argomento sia citato ma perché è inteso per i casi in cui si conosce in anticipo quale variabile è importante utilizzare per una macro per evitare di dover digitare il '.
setqrappresentaset quoted, e originariamente era una macro che si espandeva in(set 'some-variable "less"). In generale, Elisp non è molto costante circa citato vs argomenti non quotati, ma qualsiasi funzione (non macro) che deve interagire con una variabile invece di un valore prenderà suo argomento citato (setqessendo un importante eccezione).