В clojure ключевые слова оценивают себе, например:
>>:test
:test
Они не берут параметров, и они ни с чем не связываются. Почему затем, мы должны были бы квалифицировать ключевые слова в пространстве имен?
Я знаю то создание isa
использование hierachies derive
требует, чтобы пространство имен квалифицировало ключевые слова (например. ::test
). Есть ли какие-либо другие случаи, где существует ясная потребность в ключевых словах, чтобы быть в пространстве имен?
Одно место, где Clojure в настоящее время требует ключевых слов с указанием пространства имен, - это использование функции функции extend
для добавления реализации протокола к существующему типу. (Это функциональность 1.2, доступная в последних снимках состояния, но не в стабильном выпуске 1.1.) Соответствующий фрагмент из (doc extend)
:
extend принимает тип / класс (или интерфейс, см. Ниже ), и одна или несколько пар протокол + карта метода. Он расширит полиморфизм методов протокола для вызова предоставленных методов, когда в качестве первого аргумента указан AType . Обратите внимание, что типы deftype указываются с помощью их тегов ключевых слов:
:: MyType или: my.ns / MyType
Действительно, для типа Apple и протокола Eatable:
(deftype Apple [colour])
(defprotocol Eatable (eat [x]))
следующее вызывает исключение ( Нет реализации метода:: eat
и т. д.):
(extend :Apple Eatable {:eat (fn [x] (println (str (name (:colour x)) ", yummy!")))})
(eat (Apple :red))
при этом выводится красный, вкусно!
:
(extend ::Apple Eatable {:eat (fn [x] (println (str (name (:colour x)) ", yummy!")))})
(eat (Apple :red))
Обратите внимание, что я только что набрал все это в REPL. Также обратите внимание, что если вы хотите воспроизвести его, лучше всего набрать / вставить в указанном выше порядке; например переоценка любой из форм (deftype Apple [color])
и (defprotocol Eatable (eat [x]))
(или даже обеих) не заставляет Clojure забыть о реализации протокола.
Опять же, это функция версии 1.2, поэтому ее даже нет в версии 1.1, и она может измениться до фактического выпуска 1.2.
Совместное использование хеш-карты между несколькими пространствами имен - еще один возможный вариант использования, как говорит Брайан. Обратите внимание, что ссылочный тип не требуется.Скажем, есть куча библиотек - которые, возможно, будут добавлены в будущем - которые манипулируют (возможно, трансформируют, может быть, просто наблюдают) хеш-картами, привязанными к ключевым словам, где каждая библиотека может свободно определять, какие ключевые слова она ищет и какие он использует их для; тогда может возникнуть соблазн использовать ключевые слова с указанием пространства имен, чтобы избежать коллизий.
На самом деле, в настоящее время существует пример, который вовсе не является надуманным, а именно Ring spec v0.1 (ключевой элемент современной веб-экосистемы Clojure). См. Сообщение о пространстве имен ключевых слов карты запросов и ответов для группы Google Ring (составленное автором Ring
Марком МакГранаганом) для некоторого понимания причин этого проектного решения, а также за решением больше не требовать ключевые слова пространств имен в Ring spec v0.2. Также есть сообщение Джеймса Ривза (автора Compojure) в поддержку изменения.
В конечном счете, как и все пространство имен, это функция предотвращения столкновений. Код Clojure, который пишется сейчас, не заботится о "частных" ключевых словах, поэтому они не видят особой пользы; но хорошо иметь их в наличии на тот момент, когда они могут иметь значение.
Вы должны указать пространство имен своих ключевых слов, если какой-либо код когда-либо будет иметь возможность взаимодействовать с вашими ключевыми словами вне контекста вашего пространства имен. Основной пример, который я могу придумать, - это два пространства имен, помещающих ключи и значения в хэш-карту в третьем пространстве имен, где ключи являются ключевыми словами (как это часто бывает в 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
#<Ref@541b02: {: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
. Мультиметоды также часто отправляют значения ключевых слов, и нередко пространство имен определяет метод для мультиметода в другом пространстве имен. Нетрудно представить себе ситуации, когда автор библиотеки мог бы предоставить подобный механизм.
Хорошая идея - квалифицировать ключевые слова по пространству имен, если есть какой-либо риск выхода ваших ключевых слов из вашего пространства имен, если вы специально не хотите, чтобы ваши ключевые слова затирали ключевые слова из других пространств имен.