Почему 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)