¿Por qué Clojure tiene "palabras clave" además de "símbolos"?

130

Tengo un conocimiento pasajero de otros Lisps (particularmente Scheme) desde hace mucho tiempo. Recientemente he estado leyendo sobre Clojure . Veo que tiene "símbolos" y "palabras clave". Símbolos con los que estoy familiarizado, pero no con palabras clave.

¿Otros Lisps tienen palabras clave? ¿En qué se diferencian las palabras clave de los símbolos además de tener notación diferente (es decir, dos puntos)?

Laurence Gonsalves
fuente

Respuestas:

139

Aquí está la documentación de Clojure para palabras clave y símbolos.

Las palabras clave son identificadores simbólicos que se evalúan a sí mismos. Proporcionan pruebas de igualdad muy rápidas ...

Los símbolos son identificadores que normalmente se usan para referirse a otra cosa. Se pueden usar en formularios de programa para referirse a parámetros de función, enlaces, nombres de clase y variables globales ...

Las palabras clave se utilizan generalmente como "cadenas constantes" ligeras, por ejemplo, para las claves de un mapa hash o los valores de envío de un método múltiple. Los símbolos generalmente se usan para nombrar variables y funciones y es menos común manipularlos como objetos directamente, excepto en macros y demás. Pero no hay nada que le impida usar un símbolo en todas partes donde use una palabra clave (si no le importa citarlos todo el tiempo).

La forma más fácil de ver la diferencia es leer Keyword.javay Symbol.javaen la fuente Clojure. Hay algunas diferencias obvias de implementación. Por ejemplo, un símbolo en Clojure puede tener metadatos y una palabra clave no.

Además de la sintaxis de dos puntos, puede usar dos puntos para crear una palabra clave calificada para el espacio de nombres.

user> :foo
:foo
user> ::foo
:user/foo

Common Lisp tiene palabras clave, al igual que Ruby y otros idiomas. Son un poco diferentes en esos idiomas, por supuesto. Algunas diferencias entre las palabras clave Common Lisp y las palabras clave Clojure:

  1. Las palabras clave en Clojure no son símbolos.

    user> (symbol? :foo)  
    false
  2. Las palabras clave no pertenecen a ningún espacio de nombres a menos que las califique específicamente:

    user> (namespace :foo)
    nil
    user> (namespace ::foo)
    "user"

(Gracias a Rainer Joswig por darme ideas de cosas para mirar).

Brian Carper
fuente
10
Esto explica cuáles son las diferencias, pero no por qué se necesitan dos construcciones diferentes. ¿No podría Clojure haber creado algo con la unión de las capacidades de palabra clave y símbolo?
25
Las palabras clave son livianas y tienen una sintaxis conveniente, creo que eso es todo lo que hay que hacer. El lenguaje funcionaría bien sin ellos, pero es bueno tenerlos y son muy utilizados. No puede tener una unión de sus habilidades porque las palabras clave siempre se autoevalúan (es decir, no puede usarlas como nombres de variables o funciones) y los símbolos en general no siempre pueden autoevaluarse.
Brian Carper el
1
Parece palabras clave son más útiles como claves en HashMaps etc, ya que no cambian una vez evaluados: (eval (eval ':a))vs (eval (eval ''a)). ¿Hay otras ventajas? En cuanto al rendimiento, ¿son idénticos?
kristianlm
55
(¿idéntico?: qwe: qwe) -> verdadero. (¿idéntico? 'qwe' qwe) -> falso. Los símbolos usan una cadena interna, por lo que la comparación también es rápida.
desudesudesu
29

Lisp común tiene símbolos de palabras clave.

Las palabras clave también son símbolos.

(symbolp ':foo) -> T

Lo que hace que las palabras clave sean especiales:

  • : foo es analizado por el lector Common Lisp como la palabra clave del símbolo :: foo
  • las palabras clave se evalúan a sí mismas:: foo ->: foo
  • el paquete de inicio de símbolos de palabras clave es el paquete KEYWORD: palabra clave: foo ->: foo
  • las palabras clave se exportan desde el paquete PALABRA CLAVE
  • las palabras clave son constantes, no está permitido asignar un valor diferente

De lo contrario, las palabras clave son símbolos ordinarios. Por lo tanto, las palabras clave pueden nombrar funciones o tener listas de propiedades.

Recuerde: en Common Lisp, los símbolos pertenecen a un paquete. Esto se puede escribir como:

  • foo, cuando el símbolo está accesible en el paquete actual
  • foo: bar, cuando el símbolo FOO se exporta desde el paquete BAR
  • foo :: bar, cuando el símbolo FOO está en el paquete BAR

Para los símbolos de palabras clave eso significa que: foo, keyword: foo y keyword :: foo son todos el mismo símbolo. Por lo tanto, las dos últimas notaciones generalmente no se usan.

Entonces: foo solo se analiza para estar en el paquete KEYWORD, suponiendo que no dar nombre al paquete antes del nombre del símbolo significa por defecto el paquete KEYWORD.

Rainer Joswig
fuente
6

Las palabras clave son símbolos que se evalúan a sí mismas, por lo que no tiene que acordarse de citarlas.

Greg Hewgill
fuente
55
¿Es asi? Escribir: en lugar de 'no parece una gran victoria, especialmente porque: es una pulsación de tecla adicional en la mayoría de los teclados.
Laurence Gonsalves
11
Bueno, en realidad es más que solo el personaje. Las palabras clave permanecen como palabras clave después de la evaluación, mientras que los símbolos se evalúan a lo que sea que se unan. Es más como una diferencia semántica, porque generalmente se usan para diferentes propósitos.
Greg Hewgill el
13
Las palabras clave no son símbolos en Clojure
David Plumpton
4

: las palabras clave también son tratadas especialmente por muchas de las colecciones, lo que permite una sintaxis realmente conveniente.

(:user-id (get-users-map))

es lo mismo que

((get-users-map) :user-id)

esto hace que las cosas sean un poco más flexibles

Arthur Ulfeldt
fuente
21
Esto también es cierto para los símbolos, ('a {' a 1 'b 2}) => 1 y ({' a 1 'b 2}' b) => 2.
Jonas
4

Para las palabras clave, los valores hash se calculan y almacenan en caché cuando la palabra clave se construye por primera vez. Al buscar una palabra clave como una clave hash, simplemente devuelve el valor hash precalculado. Para cadenas y símbolos, el hash se recalcula en cada búsqueda.

Por qué las palabras clave con el mismo nombre son siempre idénticas, contienen sus propios valores hash. Como la búsqueda en mapas y conjuntos se realiza a partir de teclas hash, esto implica una mejor eficiencia de búsqueda en el caso de numerosas búsquedas, no en la búsqueda misma.

Ivan Pierre
fuente
0

Las palabras clave son globales , los símbolos no lo son .

Este ejemplo está escrito en JavaScript, pero espero que ayude a transmitir el punto.

const foo = Symbol.for(":foo") // this will create a keyword
const foo2 = Symbol.for(":foo") // this will return the same keyword
const foo3 = Symbol(":foo") // this will create a new symbol
foo === foo2 // true
foo2 === foo3 // false

Cuando construyes un símbolo usando la Symbolfunción, obtienes un símbolo distinto / privado cada vez. Cuando solicite un símbolo a través de la Symbol.forfunción, obtendrá el mismo símbolo cada vez.

(println :foo) ; Clojure
System.out.println(RT.keyword(null, "foo")) // Java
console.log(System.for(":foo")) // JavaScript

Estos son todos iguales.


Los nombres de argumentos de funciones son locales. es decir, no palabras clave.

(def foo (fn [x] (println x))) ; x is a symbol
(def bar (fn [x] (println x))) ; not the same x (different symbol)
John Leidegren
fuente