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

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

>>:test
:test

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

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

31
задан viebel 12 March 2012 в 07:55
поделиться

2 ответа

Одно место, где 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, который пишется сейчас, не заботится о "частных" ключевых словах, поэтому они не видят особой пользы; но хорошо иметь их в наличии на тот момент, когда они могут иметь значение.

12
ответ дан 27 November 2019 в 22:39
поделиться

Вы должны указать пространство имен своих ключевых слов, если какой-либо код когда-либо будет иметь возможность взаимодействовать с вашими ключевыми словами вне контекста вашего пространства имен. Основной пример, который я могу придумать, - это два пространства имен, помещающих ключи и значения в хэш-карту в третьем пространстве имен, где ключи являются ключевыми словами (как это часто бывает в 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 . Мультиметоды также часто отправляют значения ключевых слов, и нередко пространство имен определяет метод для мультиметода в другом пространстве имен. Нетрудно представить себе ситуации, когда автор библиотеки мог бы предоставить подобный механизм.

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

25
ответ дан 27 November 2019 в 22:39
поделиться
Другие вопросы по тегам:

Похожие вопросы: