tutorial online framework example clojure

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?

  1. El símbolo se califica para un espacio de nombre, en este caso clojure.core
  2. Luego, en alguna tabla de símbolos, está la información que + se refiere a una var
  3. 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:

  1. + es un símbolo que se encuentra en clojure.core que, de forma predeterminada, es accesible para su código.
  2. Cuando se usa en su código sin intenciones muy avanzadas, como citarlo o descubrir su clase, clojure buscará el Var al que apunta.
  3. 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