Warum hat Clojure neben "Symbolen" auch "Schlüsselwörter"?

130

Ich habe von jeher ein vorübergehendes Wissen über andere Lisps (insbesondere das Schema). Kürzlich habe ich über Clojure gelesen . Ich sehe, dass es sowohl "Symbole" als auch "Schlüsselwörter" hat. Symbole, mit denen ich vertraut bin, aber nicht mit Schlüsselwörtern.

Haben andere Lisps Schlüsselwörter? Wie unterscheiden sich Schlüsselwörter von anderen Symbolen als einer anderen Notation (dh Doppelpunkte)?

Laurence Gonsalves
quelle

Antworten:

139

Hier ist die Clojure-Dokumentation für Schlüsselwörter und Symbole.

Schlüsselwörter sind symbolische Bezeichner, die sich selbst bewerten. Sie bieten sehr schnelle Gleichstellungstests ...

Symbole sind Bezeichner, die normalerweise verwendet werden, um auf etwas anderes zu verweisen. Sie können in Programmformularen verwendet werden, um auf Funktionsparameter zu verweisen, Bindungen, Klassennamen und globale Variablen zuzulassen ...

Schlüsselwörter werden im Allgemeinen als einfache "konstante Zeichenfolgen" verwendet, z. B. für die Schlüssel einer Hash-Map oder die Versandwerte einer Multimethode. Symbole werden im Allgemeinen verwendet, um Variablen und Funktionen zu benennen, und es ist weniger üblich, sie als Objekte direkt zu bearbeiten, außer in Makros und dergleichen. Aber nichts hindert Sie daran, überall dort, wo Sie ein Schlüsselwort verwenden, ein Symbol zu verwenden (wenn es Ihnen nichts ausmacht, sie ständig zu zitieren).

Der einfachste Weg, um den Unterschied zu erkennen, ist das Lesen Keyword.javaund Symbol.javain der Clojure-Quelle. Es gibt einige offensichtliche Implementierungsunterschiede. Beispielsweise kann ein Symbol in Clojure Metadaten enthalten und ein Schlüsselwort nicht.

Zusätzlich zur Syntax mit einem Doppelpunkt können Sie einen Doppelpunkt verwenden, um ein Namespace-qualifiziertes Schlüsselwort zu erstellen.

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

Common Lisp hat Schlüsselwörter, ebenso wie Ruby und andere Sprachen. In diesen Sprachen unterscheiden sie sich natürlich geringfügig. Einige Unterschiede zwischen Common Lisp-Schlüsselwörtern und Clojure-Schlüsselwörtern:

  1. Schlüsselwörter in Clojure sind keine Symbole.

    user> (symbol? :foo)  
    false
  2. Schlüsselwörter gehören zu keinem Namespace, es sei denn, Sie qualifizieren sie speziell:

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

(Danke, Rainer Joswig, dass du mir Ideen für Dinge gegeben hast, die ich mir ansehen kann.)

Brian Carper
quelle
10
Dies erklärt , was die Unterschiede sind, aber nicht , warum zwei verschiedene Konstrukte benötigt werden . Könnte Clojure nicht etwas mit der Vereinigung der Fähigkeiten von Schlüsselwort und Symbol geschaffen haben?
25
Schlüsselwörter sind leichtgewichtig und haben eine bequeme Syntax. Ich denke, das ist alles, was dazu gehört. Die Sprache würde ohne sie gut funktionieren, aber sie sind nett zu haben und sie sind sehr weit verbreitet. Sie können ihre Fähigkeiten nicht vereinen, da Schlüsselwörter immer selbstbewertend sind (dh Sie können sie nicht als Variablen- oder Funktionsnamen verwenden) und Symbole im Allgemeinen nicht immer selbstbewertend sein können.
Brian Carper
1
Es scheint Schlüsselwörter nützlicher als Schlüssel in Hashmaps etc sind , da sie sich nicht ändern einmal ausgewertet: (eval (eval ':a))vs (eval (eval ''a)). Gibt es noch andere Vorteile? Leistungstechnisch sind sie identisch?
Kristianlm
5
(identisch ?: qwe: qwe) -> wahr. (identisch? 'qwe' qwe) -> false. Symbole verwenden intern interne Zeichenfolgen, sodass der Vergleich auch schnell ist.
Desudesudesu
29

Common Lisp hat Schlüsselwortsymbole.

Schlüsselwörter sind auch Symbole.

(symbolp ':foo) -> T

Was macht Keywords so besonders:

  • : foo wird vom Common Lisp-Reader als Symbol-Schlüsselwort :: foo analysiert
  • Schlüsselwörter bewerten sich selbst :: foo ->: foo
  • Das Home-Paket der Schlüsselwortsymbole ist das KEYWORD-Paket: keyword: foo ->: foo
  • Schlüsselwörter werden aus dem Paket KEYWORD exportiert
  • Schlüsselwörter sind Konstanten, es ist nicht erlaubt, einen anderen Wert zuzuweisen

Ansonsten sind Schlüsselwörter gewöhnliche Symbole. So können Schlüsselwörter Funktionen benennen oder Eigenschaftslisten haben.

Denken Sie daran: In Common Lisp gehören Symbole zu einem Paket. Dies kann geschrieben werden als:

  • foo, wenn das Symbol im aktuellen Paket verfügbar ist
  • foo: bar, wenn das Symbol FOO aus der Paketleiste exportiert wird
  • foo :: bar, wenn sich das Symbol FOO in der Paketleiste befindet

Für Schlüsselwortsymbole bedeutet dies, dass: foo, Schlüsselwort: foo und Schlüsselwort :: foo alle dasselbe Symbol sind. Daher werden die beiden letztgenannten Notationen normalerweise nicht verwendet.

Also: foo wird nur analysiert, um im Paket KEYWORD zu sein, vorausgesetzt, dass die Angabe eines Paketnamens vor dem Symbolnamen standardmäßig das KEYWORD-Paket bedeutet.

Rainer Joswig
quelle
6

Schlüsselwörter sind Symbole, die sich selbst bewerten, sodass Sie nicht daran denken müssen, sie zu zitieren.

Greg Hewgill
quelle
5
Ist es das? Tippen: anstatt 'scheint kein großer Gewinn zu sein, zumal: bei den meisten Tastaturen ein zusätzlicher Tastendruck ist.
Laurence Gonsalves
11
Nun, es ist wirklich mehr als nur der Charakter. Schlüsselwörter bleiben nach der Auswertung Schlüsselwörter, während Symbole nach dem ausgewertet werden, an das sie gebunden sind. Es ist eher ein semantischer Unterschied, da sie normalerweise für verschiedene Zwecke verwendet werden.
Greg Hewgill
13
Schlüsselwörter sind keine Symbole in Clojure
David Plumpton
4

: Schlüsselwörter werden auch von vielen Sammlungen speziell behandelt, was eine sehr praktische Syntax ermöglicht.

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

ist das gleiche wie

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

das macht die dinge nur ein wenig flexibler

Arthur Ulfeldt
quelle
21
Dies gilt auch für Symbole ('a {' a 1 'b 2}) => 1 und ({' a 1 'b 2}' b) => 2.
Jonas
4

Bei Schlüsselwörtern werden Hashwerte berechnet und zwischengespeichert, wenn das Schlüsselwort zum ersten Mal erstellt wird. Wenn Sie ein Schlüsselwort als Hash-Schlüssel suchen, wird einfach der vorberechnete Hash-Wert zurückgegeben. Bei Zeichenfolgen und Symbolen wird der Hash bei jeder Suche neu berechnet.

Die gleichnamigen Schlüsselwörter sind immer identisch und enthalten ihre eigenen Hashwerte. Da die Suche in Karten und Sets über Hash-Schlüssel erfolgt, bedeutet dies eine bessere Sucheffizienz bei zahlreichen Suchvorgängen, nicht bei der Suche selbst.

Ivan Pierre
quelle
0

Schlüsselwörter sind global , Symbole nicht .

Dieses Beispiel ist in JavaScript geschrieben, aber ich hoffe, es hilft, den Punkt zu vermitteln.

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

Wenn Sie ein Symbol mit der SymbolFunktion erstellen, erhalten Sie jedes Mal ein eindeutiges / privates Symbol. Wenn Sie über die Symbol.forFunktion nach einem Symbol fragen , erhalten Sie jedes Mal das gleiche Symbol zurück.

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

Diese sind alle gleich.


Funktionsargumentnamen sind lokal. dh keine Schlüsselwörter.

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