Почему Clojure имеет "ключевые слова" в дополнение к "символам"?
У меня есть попутное знание других Lisps (особенно Scheme) со стороны. Недавно я читал о Clojure. Я вижу, что он имеет как "символы", так и "ключевые слова". Символы Я знаком с, но не с ключевыми словами.
У других липсов есть ключевые слова? Как ключевые слова отличаются от символов, отличных от разных обозначений (т.е.: Colons)?
Ответы
Ответ 1
Здесь Clojure документация для ключевых слов и символов.
Ключевые слова - это символические идентификаторы, которые оцениваются сами по себе. Они обеспечивают очень быстрые тесты на равенство...
Символы - это идентификаторы, которые обычно используются для обозначения чего-то еще. Их можно использовать в программных формах для обозначения параметров функции, связывания, имена классов и глобальные вары...
Ключевые слова обычно используются как легкие "постоянные строки", например. для ключей хэш-карты или значений отправки мультиметода. Символы обычно используются для обозначения переменных и функций и менее распространены для управления ими как объектами, за исключением макросов и т.д. Но там ничего не мешает вам использовать символ везде, где вы используете ключевое слово (если вы не возражаете, цитируя их все время).
Самый простой способ увидеть разницу - прочитать Keyword.java
и Symbol.java
в источнике Clojure. Существует несколько очевидных различий в реализации. Например, Символ в Clojure может иметь метаданные, а ключевое слово не может.
В дополнение к синтаксису с одной колонкой, вы можете использовать двойную двоеточие, чтобы создать ключевое слово, соответствующее ключевому слову.
user> :foo
:foo
user> ::foo
:user/foo
Общие Lisp имеют ключевые слова, как и Ruby и другие языки. Конечно, они немного отличаются на этих языках. Некоторые различия между ключевыми словами Lisp и Clojure ключевыми словами:
-
Ключевые слова в Clojure не являются символами.
user> (symbol? :foo)
false
-
Ключевые слова не принадлежат ни одному пространству имен, если вы специально не квалифицируете их:
user> (namespace :foo)
nil
user> (namespace ::foo)
"user"
(Спасибо Райнер Йосвиг за то, что он дал мне идеи о том, что нужно посмотреть.)
Ответ 2
Общие Lisp имеют символы ключевых слов.
Ключевые слова также являются символами.
(symbolp ':foo) -> T
Что делает ключевые слова особенными:
- : foo анализируется читателем Common Lisp как символ keyword:: foo
- ключевые слова оценивают себя:: foo → : foo
- домашний пакет символов ключевых слов - это пакет KEYWORD: keyword: foo → : foo
- ключевые слова экспортируются из пакета KEYWORD
- ключевые слова - это константы, не разрешено назначать другое значение
В противном случае ключевыми словами являются обычные символы. Таким образом, ключевые слова могут называть функции или иметь списки свойств.
Помните: в Common Lisp символы относятся к пакету. Это можно записать как:
- foo, когда символ доступен в текущем пакете
- foo: bar, когда символ FOO экспортируется из пакета BAR
- foo:: bar, когда символ FOO находится в пакете BAR
Для ключевых слов, которые означают, что: foo, ключевое слово: foo и keyword:: foo - все те же символы. Таким образом, последние две записи обычно не используются.
Итак: foo просто анализируется в пакете KEYWORD, предполагая, что не указывать имя пакета до того, как имя символа по умолчанию означает пакет KEYWORD.
Ответ 3
Ключевые слова - это символы, которые оцениваются сами по себе, поэтому вам не нужно их цитировать.
Ответ 4
: ключевые слова также рассматриваются особенно многими коллекциями, что позволяет использовать некоторые действительно удобные синтаксисы.
(:user-id (get-users-map))
совпадает с
((get-users-map) :user-id)
это делает вещи немного более гибкими
Ответ 5
Для ключевых слов значения хэша вычисляются и кэшируются, когда ключевое слово
первый построенный. Когда вы просматриваете ключевое слово как хэш-ключ, он просто
возвращает предварительно вычисленное хешированное значение. Для строк и символов хэш
пересчитывается при каждом поиске.
Почему одинаковые именованные ключевые слова всегда идентичны, они содержат свои собственные значения хэша.
Поскольку поиск в картах и наборах производится из хеш-ключей, это обеспечивает лучшую эффективность поиска в случае многочисленных поисков, а не в самом поиске.
Ответ 6
Ключевые слова являются глобальными, а символы - нет.
Этот пример написан на JavaScript, но я надеюсь, что он поможет донести эту мысль до конца.
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
Когда вы создаете символ с помощью функции Symbol
, вы каждый раз получаете отдельный/закрытый символ. Когда вы запрашиваете символ с помощью функции Symbol.for
, вы будете возвращать один и тот же символ каждый раз.
(println :foo) ; Clojure
System.out.println(RT.keyword(null, "foo")) // Java
console.log(System.for(":foo")) // JavaScript
Это все одно и то же.
Имена аргументов функции являются локальными. т.е. не ключевые слова.
(def foo (fn [x] (println x))) ; x is a symbol
(def bar (fn [x] (println x))) ; not the same x (different symbol)