Подтвердить что ты не робот

Когда должны быть clojure ключевые слова в пространствах имен?

В clojure ключевые слова оцениваются сами собой, например:

>>:test
:test

Они не принимают никаких параметров и не привязаны ни к чему. Почему же тогда нам нужно квалифицировать ключевые слова в пространстве имен?

Я знаю, что для создания isa иерархии с использованием derive требуются ключевые слова с использованием пространства имен (например, ::test). Существуют ли какие-либо другие случаи, когда существует четкая потребность в ключевых словах в пространстве имен?

4b9b3361

Ответ 1

В одном месте, где Clojure в настоящее время требуются ключевые слова с именами, используется при использовании функции функции extend для добавления реализации протокола к существующему типу. (Это 1.2 функциональность, доступная с последними моментальными снимками, но не стабильная версия 1.1). Соответствующий фрагмент из (doc extend):

extend принимает тип/класс (или интерфейс, см. ниже) и один или несколько   протокол + пары методов. Это расширит полиморфизм   протокольные методы для вызова предоставленных методов, когда AType   в качестве первого аргумента. Обратите внимание, что указаны типы deftype   используя теги ключевых слов:

:: MyType или: my.ns/MyType

Действительно, для типа Apple и протокола Eatable:

(deftype Apple [colour])
(defprotocol Eatable (eat [x]))

следующее генерирует исключение (No implementation of method: :eat и т.д.):

(extend :Apple Eatable {:eat (fn [x] (println (str (name (:colour x)) ", yummy!")))})
(eat (Apple :red))

в то время как это выводит red, yummy!:

(extend ::Apple Eatable {:eat (fn [x] (println (str (name (:colour x)) ", yummy!")))})
(eat (Apple :red))

Примечание. Я только что набрал все это в REPL. Также обратите внимание, что если вы хотите воспроизвести его, вам лучше всего ввести его/вставить в приведенном выше порядке; например переоценка любой из форм (deftype Apple [colour]) и (defprotocol Eatable (eat [x])) (или даже тех и других) не делает Clojure забыть о реализации протокола.

Опять же, это функция 1.2, поэтому она даже не существует в 1.1 и может измениться до фактической версии 1.2.


Совместное использование хэш-карты между несколькими пространствами имен является еще одним возможным вариантом использования, как говорит Брайан. Обратите внимание, что нет необходимости использовать ссылочный тип. Скажите, есть куча библиотек, которые, возможно, могут быть добавлены в будущем, - которые манипулируют (возможно, преобразуют, возможно, просто наблюдают) хеш-карты с ключевыми словами, где каждая библиотека может определять, какие ключевые слова она ищет, и что он использует их; то у вас может возникнуть соблазн использовать ключевые слова с именами, чтобы избежать столкновений.

На самом деле, в настоящее время существует пример, который совсем не надуман, а именно Ring spec v0.1 (ключевой элемент сегодняшней экосистемы Clojure Web). См. сообщение о запросе на ключевое слово с именами и ответами в группу Ring Google (сделанные автором Ring
Mark McGranaghan) за некоторое понимание обоснования этого дизайнерского решения, а также за решение больше не требовать использования имен в ключевых словах в Ring spec v0.2. Там также сообщение Джеймса Ривза (автора Compojure) в поддержку изменения.


В конечном счете, как и все пространства имен, это функция предотвращения столкновений. Clojure код, который написан в настоящее время, не имеет тенденций заботиться о наличии "private" ключевых слов, поэтому они не видят большого использования; но хорошо иметь их доступными, когда они могут изменить ситуацию.

Ответ 2

Вы должны использовать пространство имен для ваших ключевых слов, если какой-либо код когда-либо будет иметь возможность взаимодействовать с вашими ключевыми словами вне контекста вашего пространства имен. Главный пример, о котором я могу думать, - это два пространства имен, которые кладут ключи и значения в хэш-карту в третьем пространстве имен, где ключевыми словами являются ключевые слова (как это часто бывает в Clojure). Надуманный пример:

user> (ns main)
nil
main> (def DATA (ref {}))
#'main/DATA
main> (ns foo)
nil
foo> (dosync (alter main/DATA assoc :bad 123 ::good 123))
{:foo/good 123, :bad 123}
foo> main/DATA
#<[email protected]: {:foo/good 123, :bad 123}>
foo> (ns bar)
nil
bar> (dosync (alter main/DATA assoc :bad 456 ::good 456))
{:bar/good 456, :foo/good 123, :bad 456}  ;; oops, no more :bad from foo

Зачем вам это нужно? Итак, некоторые основные понятия в Clojure (например, derive, например) реализованы таким образом, как хэш-карты в clojure.core. Мультиметоды также часто отправляют значения ключевых слов, и нередко для пространства имен для определения метода для мультиметода в другом пространстве имен. Нетрудно подумать о ситуациях, когда автор библиотеки может захотеть предоставить аналогичный механизм.

Это хорошая идея для пространства имен - квалифицируйте свои ключевые слова, если существует риск того, что ваши ключевые слова будут экранировать пространство имен, если только вы специально не хотите, чтобы ваши ключевые слова были сбиты с других пространств имен.