Come sapere quando o quando non utilizzare la singola virgoletta prima dei nomi delle variabili?


31

Ho il seguente:

(setq some-variable "less")

Sono confuso perché devo usare la singola citazione con boundpma non con bound-and-true-p.

Esempio 1:

(when (boundp 'some-variable) 
   (message "some-variable is %s" some-variable))

Risultato:

"alcune variabili sono meno"

Esempio 2a:

(when (bound-and-true-p some-variable) ;; Note that using single-quote causes error
   (message "some-variable is %s" some-variable))

Risultato:

"alcune variabili sono meno"

Esempio 2b:

(when (bound-and-true-p 'some-variable) ;; Note that using single-quote causes error
   (message "some-variable is %s" some-variable))

Risultato:

e: argomento di tipo errato: symbolp, (virgolette una variabile)


5
Vale la pena ricordare che setqrappresenta set 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).
shosti,

2
FWIW, bound-and-true-pè una stupida macro. O meglio, il suo nome è stupido. Il 99,99% delle volte in cui vuoi farlo (and (boundp 'FOO) FOO)lo fai per usare il valore diFOO . Non lo fai solo per ottenere un valore di verità. (1) La macro non è necessaria: il codice che sostituisce è banale e piccolo. (2) Il nome è fuorviante - riguarda il valore della variabile, non solo testare se il valore della variabile è o meno nil.
Disegnò il

Risposte:


24

Risposta breve

Se si sta tentando di utilizzare la variabile stessa, utilizzare 'some-variable. Se si sta tentando di utilizzare il valore memorizzato nella variabile, utilizzare some-variable.

  • boundp usa il simbolo in modo che guardi tutto ciò che può essere associato, comprese le funzioni. Si preoccupa solo se esiste un simbolo corrispondente, non quale sia il valore.
  • bound-and-truep usa var e restituisce il valore. In questo caso è necessario fornire il valore del simbolo alla funzione. Se nessun simbolo var è associato o il valore è zero, verrà restituito zero.

Spiegazione

Per la definizione manuale, consultare il manuale .

'ed (quote ...)entrambi svolgono lo stesso scopo in emacs-lisp.

Lo scopo è quello di passare la forma non valutata all'ambiente circostante piuttosto che valutarla.

Nel tuo esempio supponiamo che avessimo il seguente livello più in alto

(setq some-variable "less") ;; Rather than just 't for clarity

Quindi la valutazione procede come segue:

(when (boundp 'some-variable) 
   (message "some-variable is %s" some-variable))
;; ==> (boundp 'some-variable) ; 't
;; ==> some-variable is "less"

Considerando che senza un preventivo:

(when (boundp some-variable) ;; Note that using single-quote causes error
   (message "some-variable is %s" some-variable))
;; ==> (boundp "less") ; "less" is not a variable. -> Error

Lisp valuta i moduli man mano che vengono raggiunti, citando il modulo per impedire la valutazione in modo che la variabile effettiva (o elenco o nome della funzione) venga passata.


Grazie! La tua risposta mi ha fatto saltare nelle fonti di entrambi e mi ha aiutato a trovare la soluzione. Ho anche aggiornato la mia domanda con chiari esempi.
Kaushal Modi,

6
Sono contento che questo abbia aiutato l'operazione, ma in realtà non risponde alla domanda (in un modo utile per altre persone che hanno la stessa domanda). Spieghi solo che i simboli devono essere citati, altrimenti vengono valutati. Non spieghi perché non è il caso bound-and-truepe la domanda era perché devo citare quando uso boundpma non quando uso bound-and-truep.
tarsius,

@tarsius In realtà includo la distinzione tra boundprichiedere un simbolo (non valutato) e bound-and-truepaver bisogno del valore della variabile nei punti elenco (modificato dopo la risposta iniziale)
Jonathan Leech-Pepin,

Penso che sia essenziale menzionare il motivo per cui (le macro possono scegliere di non valutare) invece di menzionare semplicemente la stringa di documenti. Penso che questa sia un'ottima domanda e che boundp vs. bound-and-true-p sia solo un esempio. Ciò a cui si riduce davvero la domanda è il desiderio di conoscere le regole di valutazione.
tarsius,

@tarsius Le regole di valutazione non sono spiegate da questa risposta? Almeno quelli di base che coinvolgono solo la citazione ... La tua risposta è decisamente più completa, ma va ben oltre l'argomento, non è vero?
T. Verron,

17

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 '.


Incredibilmente ben risposto.
Charles Ritchie,

2

Dal codice sorgente di boundp:

DEFUN ("boundp", Fboundp, Sboundp, 1, 1, 0,
      doc: /* Return t if SYMBOL's value is not void.
Note that if `lexical-binding' is in effect, this refers to the
global value outside of any lexical scope.  */)

boundpsi aspetta un symbolinput. 'some-variableè un simbolo della variabile some-variable.

Dal codice sorgente di bound-and-true-p:

(defmacro bound-and-true-p (var)
  "Return the value of symbol VAR if it is bound, else nil."
  `(and (boundp (quote ,var)) ,var))

bound-and-true-psi aspetta un variableinput.

All'interno della bound-and-true-pmacro, ottiene il simbolo facendo (quote ,var). Quindi, se l'input è some-variable, (quote ,var)si tradurrà in 'some-variable.

Ma quando do l'input 'some-variablea bound-and-true-p, ottengo l'errore: and: Wrong type argument: symbolp, (quote some-variable)perché la macro NON si aspetta un simbolo ( 'some-variable) sull'input.


Solo un avviso. ''symbol ha senso. Significa (quote (quote symbol)). Il motivo per cui ricevi un errore è che non è un argomento valido per boundp.
Malabarba,

@Malabarba Grazie. Ho apportato la correzione.
Kaushal Modi,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.