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 variable
non 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-variable
associato come variabile" e non "è il simbolo my-variable
associato come variabile.
Quindi perché si bound-and-truep
comporta 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-p
come 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 nil
se my-variable
non lo è boundp
oppure 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 quote
per 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-p
anche è una macro del lettore. Se cita un simbolo come in `symbol
esso 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 quote
per impedire la valutazione di un simbolo.
Ma perché bound-and-true-p
una macro boundp
non 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' boundp
argomento fosse automaticamente citato.
bound-and-true-p
viene 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-p
potrebbe 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 '
.
setq
rappresentaset 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 (setq
essendo un importante eccezione).