Un símbolo que se encuentra en una posición sin función se trata como el nombre de una variable. In (function variable) functionestá en posición de función (después del paréntesis de apertura) y variableno 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-variablevinculada como una variable" y no "es el símbolo my-variablevinculado como una variable.
Entonces, ¿por qué se bound-and-truepcomporta 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-pcomo 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 nilsi my-variableno es boundpo 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 quotees 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 quotepara 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-ptambién es una macro lectora. Si cita un símbolo como en `symboles 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 quotepara evitar que un símbolo sea evaluado.
¿Pero por qué es bound-and-true-puna macro mientras boundpque 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 boundpargumento se citara automáticamente.
bound-and-true-pse 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-ppodrí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 '.
setqsignificaset 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 (setqsiendo una excepción importante).