online - Diferencia entre símbolos y Vars en Clojure
clojure web framework (3)
Consulte la documentación de espacios de nombres :
Los espacios de nombres son asignaciones de símbolos simples (no calificados) a Vars y / o Clases. Los Vars pueden ser internados en un espacio de nombres, usando def o cualquiera de sus variantes, en cuyo caso tienen un símbolo simple para un nombre y una referencia a su espacio de nombres contenedor, y el espacio de nombres asigna ese símbolo a la misma var. Un espacio de nombre también puede contener asignaciones desde símbolos a vars internados en otros espacios de nombres mediante el uso de referir o usar, o desde símbolos a objetos de Clase mediante el uso de importación.
Entonces, básicamente, sus pasos 1 y 2 están unificados: los espacios de nombres son las tablas de símbolos.
Y con respecto al paso 3: me gusta la definición de variables que son combinaciones de nombres de valores. El símbolo es el nombre de la variable y su evaluación dará como resultado su valor.
Siempre estoy un poco confundido sobre Símbolos y Vars en Clojure. Por ejemplo, ¿es seguro decir que + es un símbolo que se utiliza para denotar una var, y este var apunta a un valor que es una función que puede agregar números?
Entonces, ¿qué sucede, paso a paso cuando acabo de ingresar "+" en un REPL?
- El símbolo se califica para un espacio de nombre, en este caso clojure.core
- Luego, en alguna tabla de símbolos, está la información que + se refiere a una var
- Cuando se evalúa esta var, ¿el resultado es un valor de función?
Esta respuesta no es muy diferente de las otras, simplemente no supone que originalmente desea aprender varias funciones y conceptos nuevos solo para comprender lo que está sucediendo:
-
+
es un símbolo que se encuentra enclojure.core
que, de forma predeterminada, es accesible para su código. - Cuando se usa en su código sin intenciones muy avanzadas, como citarlo o descubrir su clase, clojure buscará el Var al que apunta.
- Si este Var es una función, cuando
+
se utiliza en la posición de la cabeza de una lista, clojure intentará llamar a esa función (NullPointerException
si este Var no apuntó a una función). Si se proporciona como argumento para otra función, esa función puede hacer lo mismo para llamarlo. Así es como funciona la función de llamadas.
más comentarios para redondear:
La mayoría o todos los idiomas usan tablas de símbolos. Siendo un lenguaje algo dinámico, Clojure usa esta capa adicional de indirección (Símbolo → Var → función, en lugar de solo Símbolo → función) para que reescribir dinámicamente qué función esté vinculada a qué símbolo - sea más factible y elegante, y esto a veces es una fuente de curiosidad para principiantes.
Como otras respuestas han enfatizado un poco demasiado, de lo contrario puede realizar cosas sofisticadas como citarlo ( ''+
) para evitar su evaluación, o incluso inspeccionarlo con class
y / o resolve
como si estuviera interesado en verificar qué es ( class
), o en qué espacio de nombres se encuentra ( resolve
). También puede presionar en var var puntos en via var
o #''
. Por lo general, hará esas cosas fantásticas si está escribiendo macros o si tiene una inclinación muy experimental, especialmente cuando trabaja en el repl; dependiendo del estilo en que escribas tus macros, en realidad puedes citar bastantes en ellas.
y una ilustración elegante para la persona extra-exploratoria:
Siendo un lenguaje un tanto flexible, clojure expone api para tomar la función Symbol → Var → caminar por su cuenta. Normalmente, nunca harías eso solo por usar una función, porque obviamente sería aburrido y redundante, pero se puede usar aquí para ilustrar el proceso:
(deref (resolve ''+))
A saber, el símbolo se resuelve primero en su Var, luego se llega a lo que apunta el Var. Esto simplemente ilustra el proceso de 2 pasos para llegar a una función (Símbolo → Var → función), que ocurre detrás de las escenas. Espero que hayas evitado leer esta parte extra.
TL; DR
la respuesta a la pregunta original es simple: sí.
Hay un símbolo + del que puedes hablar al citarlo:
user=> ''+
+
user=> (class ''+)
clojure.lang.Symbol
user=> (resolve ''+)
#''clojure.core/+
Entonces resuelve # ''+, que es un Var:
user=> (class #''+)
clojure.lang.Var
El Var hace referencia al objeto función:
user=> (deref #''+)
#<core$_PLUS_ clojure.core$_PLUS_@55a7b0bf>
user=> @#''+
#<core$_PLUS_ clojure.core$_PLUS_@55a7b0bf>
(El signo @ es solo una abreviatura de deref.) Por supuesto, la forma habitual de acceder a la función es no citar el símbolo:
user=> +
#<core$_PLUS_ clojure.core$_PLUS_@55a7b0bf>
Tenga en cuenta que los enlaces léxicos son un mecanismo diferente, y pueden sombrear Vars, pero puede eludirlos al referirse al Var explícitamente:
user=> (let [+ -] [(+ 1 2) (@#''+ 1 2)])
[-1 3]
En ese último ejemplo, el deref incluso se puede omitir:
user=> (let [+ -] [(+ 1 2) (#''+ 1 2)])
[-1 3]
Esto se debe a que Var implementa IFn (la interfaz para las funciones de Clojure) llamando a deref sobre sí mismo, lanzando el resultado a IFn y delegando la llamada de función a eso.
El mecanismo de visibilidad utilizado cuando define funciones privadas con defn- se basa en los metadatos del símbolo. Puede eludirlo al referirse directamente al Var, como se indica arriba:
user=> (ns foo)
nil
foo=> (defn- private-function [] :secret)
#''foo/private-function
foo=> (in-ns ''user)
#<Namespace user>
user=> (foo/private-function)
java.lang.IllegalStateException: var: #''foo/private-function is not public (NO_SOURCE_FILE:36)
user=> (#''foo/private-function)
:secret