Perché Clojure ha "parole chiave" oltre a "simboli"?


130

Ho una conoscenza passante di altri Lisps (in particolare Scheme) di ritorno. Di recente ho letto di Clojure . Vedo che ha sia "simboli" che "parole chiave". Simboli con cui ho familiarità, ma non con parole chiave.

Altre Lisps hanno parole chiave? In che modo le parole chiave sono diverse dai simboli diversi dalla notazione diversa (es. Due punti)?


Risposte:


139

Ecco la documentazione Clojure per parole chiave e simboli.

Le parole chiave sono identificatori simbolici che valutano se stessi. Forniscono test di uguaglianza molto veloci ...

I simboli sono identificatori che vengono normalmente utilizzati per fare riferimento a qualcos'altro. Possono essere utilizzati nei moduli del programma per fare riferimento a parametri di funzione, lasciare collegamenti, nomi di classe e variabili globali ...

Le parole chiave vengono generalmente utilizzate come "stringhe costanti" leggere, ad esempio per le chiavi di una mappa hash o i valori di invio di un metodo multiplo. I simboli sono generalmente usati per nominare variabili e funzioni ed è meno comune manipolarli come oggetti direttamente tranne che nelle macro e simili. Ma non c'è nulla che ti impedisca di usare un simbolo ovunque usi una parola chiave (se non ti dispiace citarli continuamente).

Il modo più semplice per vedere la differenza è leggere Keyword.javae Symbol.javanella fonte Clojure. Ci sono alcune evidenti differenze di implementazione. Ad esempio, un simbolo in Clojure può avere metadati e una parola chiave no.

Oltre alla sintassi a due punti, è possibile utilizzare due punti per creare una parola chiave qualificata per lo spazio dei nomi.

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

Lisp comune ha parole chiave, così come Ruby e altre lingue. Naturalmente sono leggermente diversi in quelle lingue. Alcune differenze tra parole chiave Lisp comuni e parole chiave Clojure:

  1. Le parole chiave in Clojure non sono simboli.

    user> (symbol? :foo)  
    false
  2. Le parole chiave non appartengono a nessuno spazio dei nomi a meno che non le qualifichi specificamente:

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

(Grazie Rainer Joswig per avermi dato idee sulle cose da guardare.)


10
Questo spiega quali sono le differenze, ma non perché sono necessari due diversi costrutti. Clojure non avrebbe potuto creare qualcosa con l'unione delle capacità di Parola chiave e Simbolo?

25
Le parole chiave sono leggere e hanno una sintassi conveniente, penso che sia tutto ciò che c'è da fare. La lingua funzionerebbe bene senza di loro, ma sono belli da avere e sono molto usati. Non puoi avere un'unione delle loro capacità perché le parole chiave sono sempre auto-valutanti (cioè non puoi usarle come nomi di variabili o funzioni) e i simboli in generale non possono essere sempre auto-valutati.
Brian Carper,

1
Sembra che le parole chiave sono più utili come chiavi in HashMaps ecc in quanto non cambiano una volta valutati: (eval (eval ':a))vs (eval (eval ''a)). Ci sono altri vantaggi? Per quanto riguarda le prestazioni, sono identici?
kristianlm,

5
(identico?: qwe: qwe) -> vero. (identico? 'qwe' qwe) -> false. I simboli usano una stringa interna all'interno, quindi anche il confronto è veloce.
desudesudesu,

29

Lisp comune ha simboli di parole chiave.

Anche le parole chiave sono simboli.

(symbolp ':foo) -> T

Cosa rende speciali le parole chiave:

  • : foo è analizzato dal lettore Common Lisp come parola chiave simbolo :: foo
  • le parole chiave valutano se stesse:: foo ->: foo
  • il pacchetto home dei simboli delle parole chiave è il pacchetto KEYWORD: parola chiave: foo ->: foo
  • le parole chiave vengono esportate dal pacchetto KEYWORD
  • le parole chiave sono costanti, non è consentito assegnare un valore diverso

Altrimenti le parole chiave sono simboli ordinari. Quindi le parole chiave possono nominare funzioni o avere elenchi di proprietà.

Ricorda: in Common Lisp i simboli appartengono a un pacchetto. Questo può essere scritto come:

  • pippo, quando il simbolo è accessibile nel pacchetto corrente
  • foo: bar, quando il simbolo FOO viene esportato dal pacchetto BAR
  • foo :: bar, quando il simbolo FOO è nel pacchetto BAR

Per i simboli di parole chiave ciò significa che: pippo, parola chiave: pippo e parola chiave :: pippo sono tutti lo stesso simbolo. Pertanto, le ultime due notazioni non vengono generalmente utilizzate.

Quindi: foo è appena analizzato per essere nel pacchetto KEYWORD, supponendo che non dare un nome al pacchetto prima del nome del simbolo significhi per impostazione predefinita il pacchetto KEYWORD.


6

Le parole chiave sono simboli che si valutano da sole, quindi non devi ricordare di citarle.


5
È così? Digitare: piuttosto che "non sembra una grande vittoria, soprattutto perché: è un tasto in più sulla maggior parte delle tastiere.
Laurence Gonsalves,

11
Bene, è molto più che il solo personaggio, davvero. Le parole chiave rimangono parole chiave dopo la valutazione, mentre i simboli vengono valutati in base a ciò a cui si legano. È più simile a una differenza semantica, perché in genere vengono utilizzati per scopi diversi.
Greg Hewgill,

13
Le parole chiave non sono simboli in Clojure
David Plumpton,

4

: le parole chiave sono anche trattate appositamente da molte raccolte, consentendo una sintassi davvero conveniente.

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

equivale a

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

questo rende le cose solo un po 'più flessibili


21
Questo vale anche per i simboli, ('a {' a 1 'b 2}) => 1 e ({' a 1 'b 2}' b) => 2.
Jonas,

4

Per le parole chiave, i valori di hash vengono calcolati e memorizzati nella cache quando la parola chiave viene costruita per la prima volta. Quando si cerca una parola chiave come chiave hash, restituisce semplicemente il valore con hash precompilato. Per stringhe e simboli, l'hash viene ricalcolato su ogni ricerca.

Le parole chiave con lo stesso nome sono sempre identiche, contengono i propri valori di hash. Poiché la ricerca nelle mappe e nei set viene effettuata da chiavi hash, ciò comporta una migliore efficienza di ricerca in caso di numerose ricerche, non nella ricerca stessa.


0

Le parole chiave sono globali , i simboli no .

Questo esempio è scritto in JavaScript, ma spero che possa essere d'aiuto.

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

Quando costruisci un simbolo usando la Symbolfunzione ottieni ogni volta un simbolo distinto / privato. Quando si richiede un simbolo tramite la Symbol.forfunzione, si ottiene lo stesso simbolo ogni volta.

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

Questi sono tutti uguali.


I nomi degli argomenti delle funzioni sono locali. cioè non parole chiave.

(def foo (fn [x] (println x))) ; x is a symbol
(def bar (fn [x] (println x))) ; not the same x (different symbol)
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.