Un símbolo que se encuentra en una posición sin función se trata como el nombre de una variable. In (function variable)
function
está en posición de función (después del paréntesis de apertura) y variable
no lo está. A menos que las variables citadas explícitamente se reemplacen con sus valores.
Si (boundp my-variable)
tuviera que escribir eso significaría "es el símbolo que se almacena en el valor de la variable my-variable
vinculada como una variable" y no "es el símbolo my-variable
vinculado como una variable.
Entonces, ¿por qué se bound-and-truep
comporta de manera diferente?
Esta es una macro y las reglas normales de evaluación (función) no se aplican aquí, las macros son libres de decidir si se evalúan sus argumentos y cuándo. Lo que las macros realmente hacen es de alguna manera transformar los argumentos y devolver el resultado como una lista, que luego se evalúa. La transformación y la evaluación final ocurren en diferentes momentos, llamados tiempo de macroexpansión y tiempo de evaluación.
Así es bound-and-true-p
como se ve la definición de :
(defmacro bound-and-true-p (var)
"Return the value of symbol VAR if it is bound, else nil."
`(and (boundp (quote ,var)) ,var))
Esto usa macros de lector que son diferentes de las macros de lisp (más sobre eso a continuación). Para no complicar esto aún más, no usemos ninguna macro de lector:
(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))
Si tú escribes
(bound-and-true-p my-variable)
que primero se "traduce" a
(and (boundp 'my-variable) my-variable)
y luego se evalúa devolviendo nil
si my-variable
no es boundp
o de lo contrario el valor de my-variable
(que por supuesto también puede ser nil
).
Es posible que hayas notado que la expansión no fue
(and (boundp (quote my-variable)) my-variable)
como podríamos haber esperado quote
es una forma especial, no una macro o función. Al igual que las macros, las formas especiales pueden hacer lo que sea con sus argumentos. Esta forma especial en particular simplemente devuelve su argumento, aquí un símbolo, en lugar del valor variable del símbolo. Ese es en realidad el único propósito de esta forma especial: ¡evitar la evaluación! Las macros no pueden hacer eso por sí mismas, necesitan usarlas quote
para hacerlo.
Entonces, ¿qué pasa '
? Es una macro lectora , que como se mencionó anteriormente no es lo mismo que una macro lisp . Mientras que las macros se usan para transformar código / datos, las macros de lector se usan antes cuando se lee texto para transformar ese texto en código / datos.
'something
es una forma corta de
(quote something)
`
utilizado en la definición real de bound-and-true-p
también es una macro lectora. Si cita un símbolo como en `symbol
es equivalente a 'symbol
, pero cuando se usa para citar una lista como en, `(foo bar ,baz)
se comporta de manera diferente en la medida en que ,
se evalúan los formularios con prefijo .
`(constant ,variable)
es equivalente a
(list (quote constant) variable))
Esto debería responder a la pregunta de por qué los símbolos sin comillas a veces se evalúan (reemplazan con sus valores) y otras no; Las macros pueden usarse quote
para evitar que un símbolo sea evaluado.
¿Pero por qué es bound-and-true-p
una macro mientras boundp
que no lo es? Tenemos que poder determinar si los símbolos arbitrarios, que no se conocen hasta el tiempo de ejecución, están vinculados como símbolos. Esto no sería posible si el boundp
argumento se citara automáticamente.
bound-and-true-p
se usa para determinar si se define una variable conocida y, en caso afirmativo, usar su valor. Esto es útil si una biblioteca tiene una dependencia opcional en una biblioteca de terceros como en:
(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
podría definirse como una función y requerir que se cite el argumento, pero porque está destinado a casos en los que sabe por adelantado qué variable le importa una macro se usó para evitar que tenga que escribir el '
.
setq
significaset quoted
, y originalmente era una macro que se expandió en(set 'some-variable "less")
. En general, Elisp no es terriblemente coherente con los argumentos entre comillas y sin comillas, pero cualquier función (no macro) que necesite interactuar con una variable en lugar de un valor tomará su argumento entre comillas (setq
siendo una excepción importante).