namespaces clojure keyword

namespaces - ¿Cuándo deben estar las palabras clave de clojure en los espacios de nombres?



keyword (2)

Debe calificar sus palabras clave en el espacio de nombres si algún código alguna vez tendrá la oportunidad de interactuar con sus palabras clave fuera del contexto de su espacio de nombres. El ejemplo principal en el que puedo pensar es en dos espacios de nombres que ponen claves y valores en un hash-map en un tercer espacio de nombres, donde las claves son palabras clave (como suele ocurrir en Clojure). Un ejemplo artificial:

user> (ns main) nil main> (def DATA (ref {})) #''main/DATA main> (ns foo) nil foo> (dosync (alter main/DATA assoc :bad 123 ::good 123)) {:foo/good 123, :bad 123} foo> main/DATA #<Ref@541b02: {:foo/good 123, :bad 123}> foo> (ns bar) nil bar> (dosync (alter main/DATA assoc :bad 456 ::good 456)) {:bar/good 456, :foo/good 123, :bad 456} ;; oops, no more :bad from foo

Por qué querrías hacer esto? Bueno, algunos conceptos básicos en Clojure (como derive , por ejemplo) se implementan de esta manera, como hash-maps en clojure.core . Los métodos múltiples también suelen enviar valores de palabras clave, y no es raro que un espacio de nombres defina un método para un método múltiple en otro espacio de nombres. No es difícil pensar en situaciones en las que al autor de una biblioteca le gustaría proporcionar un tipo similar de mecanismo.

Es una buena idea calificar las palabras clave en el espacio de nombre si existe algún riesgo de que sus palabras clave escapen de su espacio de nombres, a menos que desee específicamente que sus palabras clave eliminen aquellas de otros espacios de nombres.

En clojure, las palabras clave se evalúan a sí mismas, por ejemplo:

>>:test :test

No toman ningún parámetro, y no están limitados a nada. ¿Por qué entonces, necesitaríamos calificar palabras clave en un espacio de nombres?

Sé que la creación de jerarquías isa utilizando derive requiere palabras clave calificadas para el espacio de nombres (por ejemplo, ::test ). ¿Hay algún otro caso en el que exista una clara necesidad de que las palabras clave estén en un espacio de nombres?


Un lugar donde Clojure actualmente requiere palabras clave calificadas para el espacio de nombres es cuando se usa la función de función de extend para agregar una implementación de un protocolo a un tipo existente. (Esta es la funcionalidad 1.2, disponible con las últimas instantáneas, pero no la versión estable 1.1.) El fragmento relevante de (doc extend) :

extender toma un tipo / clase (o interfaz, ver abajo), y uno o más pares de protocolo + mapa de métodos. Se ampliará el polimorfismo de los métodos del protocolo para llamar a los métodos suministrados cuando se proporciona un AType como primer argumento. Tenga en cuenta que los tipos de deftype se especifican utilizando sus etiquetas de palabras clave:

:: MyType o: my.ns / MyType

De hecho, para un tipo de Apple y un protocolo de Eatable:

(deftype Apple [colour]) (defprotocol Eatable (eat [x]))

lo siguiente arroja una excepción ( No implementation of method: :eat etc.):

(extend :Apple Eatable {:eat (fn [x] (println (str (name (:colour x)) ", yummy!")))}) (eat (Apple :red))

Mientras esto se imprime red, yummy! :

(extend ::Apple Eatable {:eat (fn [x] (println (str (name (:colour x)) ", yummy!")))}) (eat (Apple :red))

Tenga en cuenta que acabo de escribir todo en REPL. También tenga en cuenta que si desea reproducirlo, es mejor que lo escriba / pegue en el orden indicado anteriormente; por ejemplo, reevaluar cualquiera de las (deftype Apple [colour]) y (defprotocol Eatable (eat [x])) (o incluso ambas) no hace que Clojure se olvide de la implementación del protocolo.

De nuevo, esta es una característica 1.2, por lo que ni siquiera está en 1.1 y podría cambiar antes de la versión actual de 1.2.

Compartir un hash-map entre varios espacios de nombres es otro posible caso de uso, como dice Brian. Tenga en cuenta que no es necesario involucrar un tipo de referencia. Supongamos que hay un montón de bibliotecas, que tal vez se puedan agregar en el futuro, que manipulen (quizás transformen, quizás solo observen) hash-maps codificados por palabras clave, donde cada biblioteca es libre de definir qué palabras clave busca y qué los usa para; entonces uno podría estar tentado de usar palabras clave calificadas para el espacio de nombres para evitar colisiones.

En realidad, actualmente existe un ejemplo que no se concibe en absoluto, es decir, la especificación Ring v0.1 (una pieza clave del ecosistema actual de Clojure Web). Consulte el mensaje Solicitud de correspondencia y el espacio de palabras clave del mapa de respuesta para el grupo Ring Google (creado por Ring author
Mark McGranaghan) para obtener una idea de la razón detrás de la decisión de diseño, así como detrás de la decisión de que ya no se requieren palabras clave con espacios de nombre en la especificación de Ring v0.2. También hay un mensaje de James Reeves (el autor de Compojure) en apoyo del cambio.

En última instancia, como todos los espacios de nombres, esta es una función para evitar colisiones. El código de Clojure que se escribe hoy en día no suele preocuparse por tener palabras clave "privadas", por lo que no se usan mucho; pero es bueno tenerlos disponibles para cuando puedan hacer la diferencia.