tutorial online example clojure

online - clojurescript



Símbolos en Clojure (2)

¿Cuál es la razón para que los Símbolos en Clojure estén vinculados a un objeto subyacente y tengan un valor separado opcional? Tal vez me falte algo elemental, pero sería genial si alguien pudiera señalar el Porqué.


Introducción general:

Los símbolos en cualquier Lisp se utilizan como identificadores. Si va a referirse al valor de una variable, digamos, necesita tener una forma de nombrarla; para eso son los símbolos Recuerde que todo el código Lisp se traduce en tiempo de lectura a las estructuras de datos de Lisp; Los identificadores también deben estar representados por alguna estructura de datos y es el símbolo. Al encontrar un símbolo, eval envía a algún tipo de operación de "búsqueda de nombre".

Al pasar de las generalidades de Lisp a los detalles de Clojure, el comportamiento de Clojure eval / compiler es que al encontrar un símbolo, lo toma como un nombre para una variable local o un parámetro de función introducido por el usuario o el nombre de una entrada en un espacio de nombres . En realidad, solo se pueden usar símbolos no calificados para el espacio de nombres en la primera capacidad (es decir, símbolos de la forma foo y no some-namespace/foo ).

Un ejemplo aproximadamente esbozado:

Para un foo símbolo no calificado en el espacio de nombres, si se encuentra un parámetro let bind / function de name foo , el símbolo se evalúa a su valor. Si no, el símbolo se transforma a la forma *ns*/foo ( *ns* denota el espacio de nombres actual) y se intenta buscar una entrada correspondiente en *ns* ; si existe tal entrada, se devuelve su valor; de lo contrario, se lanza una excepción.

Tenga en cuenta que un símbolo como identity , cuando se usa en quux espacio de nombres, se resolverá en clojure.core/identity través de un paso intermedio en el que se descubre una entrada bajo quux/identity ; Esto normalmente se referirá a clojure.core/identity . Ese es un detalle de implementación en el que uno no piensa cuando codifica de forma intuitiva, pero que me resulta imposible no mencionar al intentar explicar esto.

Se buscará un símbolo que ya esté calificado para el espacio de nombres (algo así como un zip/root en un espacio de nombres que clojure.zip refer a clojure.zip sin use ) en el espacio de nombres apropiado.

Hay algo de complejidad adicional con las macros (que solo puede ocurrir en la posición del operador), pero en realidad no es algo relevante para el comportamiento de los símbolos en sí.

Vars vs Símbolos:

Tenga en cuenta que, en Clojure, los símbolos no son ubicaciones de almacenamiento, sino que los vars son. Entonces, cuando digo en la parte superior que un símbolo se busca en un espacio de nombres, lo que quiero decir es que eval busca el Var que lleva el símbolo resuelto a su forma de espacio de nombres calificado y luego toma el valor de eso. La forma especial var (a menudo abreviada como #'' ) modifica este comportamiento para que se devuelva el propio objeto Var. Sin embargo, la mecánica de la resolución de símbolo a var no ha cambiado.

Observaciones finales:

Tenga en cuenta que todo esto significa que los símbolos solo están "vinculados" a los objetos en el sentido de que eval , cuando evalúa un símbolo, busca otro objeto más. El símbolo en sí no tiene "ranura" o "campo" para que un objeto esté vinculado a él; cualquier impresión de que un símbolo está "vinculado" a algún objeto se debe al funcionamiento de eval . Esta es una característica de Clojure, ya que en algunos símbolos de Lisps actúan como ubicaciones de almacenamiento.

Finalmente, se puede usar el mecanismo de cotización habitual para evitar la evaluación de un símbolo: en ''foo , el símbolo foo no se evaluará (por lo que no se realizará ninguna búsqueda de nombres); será devuelto sin cambios en su lugar.

En respuesta al comentario de OP: Prueba esto por diversión:

(defmacro symbol?? [x] (if (symbol? x) true false)) (def s 1) (symbol? s) ; => false (symbol?? s) ; => true (symbol? ''s) ; => true (symbol?? ''s) ; => false

El último explicado: ''s es una abreviatura de (quote s) ; Esta es una estructura de lista, no un símbolo. Una macro opera sobre sus argumentos pasados ​​directamente, sin ser evaluada; así que en (symbol?? ''s) realmente ve la estructura de la lista (quote s) , que por supuesto no es un símbolo en sí misma, aunque cuando se pasa a eval , se evalúa a uno.


Puede haber cierta confusión aquí por los diferentes usos del término "símbolo" en Common Lisp y en Clojure.

En Common Lisp, un "símbolo" es una ubicación en la memoria, un lugar donde se pueden almacenar los datos. El "valor" de un símbolo son los datos almacenados en esa ubicación en la memoria.

En Clojure, un "símbolo" es solo un nombre. No tiene valor.

Cuando el compilador de Clojure encuentra un símbolo, intenta resolverlo como

  1. un nombre de clase de Java (si el símbolo contiene un punto)
  2. un local (como con "let" o parámetros de función)
  3. una var en el espacio de nombres actual
  4. una var referida desde otro espacio de nombres

El Var, como se señaló en un póster anterior, representa un lugar de almacenamiento.

Hay buenas razones por las que Clojure separa Vars de los símbolos. Primero, evita la molestia de los símbolos internados automáticamente de Common Lisp, que pueden "contaminar" un paquete con símbolos no deseados.

En segundo lugar, Clojure Vars tiene una semántica especial con respecto a la concurrencia. Un Var tiene exactamente un "enlace de raíz" visible para todos los subprocesos. (Cuando escribe "def", está configurando el enlace raíz de un Var.) Los cambios en un Var realizados dentro de un hilo (usando "set!" O "enlace") son visibles solo para ese hilo y sus hijos.