Почему клавиши и валы не работают на векторах?

Я часто оказываюсь в ситуации, когда мне действительно все равно, есть ли у меня вектор или карта:

[:foo :bar :baz :qux]
{0 :foo, 1 :bar, 2 :baz, 3 :qux}

Важные функции (get, assoc и т.д.) работают на обоих. Некоторые, например, dissoc, не работают на векторах, но у них есть веские причины не делать этого.

Однако я просто не понимаю, почему keys и vals работают на картах, а не на векторах. Есть ли веская причина, почему они не реализованы что-то вроде этого (или, может быть, с более элегантным, полиморфным решением)?

(defn keys [m]
  (if (vector? m)
    (seq (range (count m)))
    (clojure.lang.RT/keys m)))

(defn vals [m]
  (if (vector? m)
    (seq m)
    (clojure.lang.RT/vals m)))

Если нет веской причины, как я могу попытаться реализовать это в стандартном Clojure?

Ответ 1

Я думаю, что это хорошая идея, заслуживающая внимания.

Вопрос о том, с какими функциями следует работать и что должно быть ошибкой, сложно провести линию. С одной стороны, язык может быть чрезмерно разрешительным (JavaScript?) До такой степени, что он позволяет вам навредить себе. На другом конце это может быть настолько предписывающим, что вы остаетесь без мощных абстракций, которые составляют (C?).

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

Мне было бы странно называть keys вектором, потому что вектор не имеет ключей, он индексируется. Для меня это разные вещи. Поэтому, если я пишу код, который вызывает keys на векторе, это, вероятно, ошибка. Если я действительно хочу, чтобы диапазон был того же размера, что и счет вектора, я бы это явно написал. И если бы я хотел иметь функцию, которая могла бы обрабатывать как карты, так и векторы, я бы использовал условный тип для выбора ключей или подсчета диапазонов. Очевидно, это только мои предпочтения, но для меня они являются серьезной причиной, чтобы не хотеть keys работать над векторами. В частности, причина в том, что я хочу обнаружить ошибки.

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

Как и в случае dissoc, кто-то может потребовать, почему нет? (dissoc [1 2 3] 0) -> [2 3]) Есть проблема с производительностью, потому что вы не можете удалить элементы в O (1), ну, действительно, если Clojure принят rbb-vector, Это очень удобно иногда, когда вам нужно выполнить эту операцию. что-то нужно делать людям, и это довольно уродливо и непрозрачно в Clojure! Никто из нас не хочет, чтобы это была функция, но я уверен, что в некоторых ситуациях она будет очень изящной. Но на самом деле это не случайное ограничение, мы просто так предпочитаем.

Clojure имеет открытый вклад, который сводится к: Обсудите, что вы пытаетесь сделать с другими в группе Clojure Dev Google. Theyre, вероятно, сможет предложить комментарии и предложения, которые приведут к более качественным изменениям и более плавному процессу подачи. После того, как вы отправили CA, вы можете отправлять патчи через JIRA.

Любой может отправить запрос об ошибке или расширении на Clojure. Любой, кто подписал соглашение о спонсорстве, может предоставить исправления или работать над улучшением билетов. Проселочным лицам была предоставлена ​​возможность переместить билеты через (некоторые из) этапов процесса. BDFL - Рик Хикки - создатель и доброжелательный диктатор для жизни того, что входит в Clojure. Стюарт Хэллоуэй также имеет специальный уровень доступа и обычно фиксирует исправления до Clojure.

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

Ответ 2

В качестве фона re модель коллекции: http://insideclojure.org/2016/03/16/collections/

Ключи и vals определяются как функции, которые выполняют выборку записей карты. Учитывая это определение, нетрудно расширить его, чтобы также взять коллекцию с ассоциативным признаком, потому что коллекция, подобная вектору, не будет генерировать seq записей, а скорее seq векторных значений. Возможность seq для сопоставления записей - это то, что предоставляется только картами.

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

К дизайну вопрос о том, должно ли это быть сделано таким образом или нет в первую очередь, это труднее мне сказать.