В Clojure как деструктурировать все ключи карты? - PullRequest
9 голосов
/ 19 февраля 2012

В ближайшем будущем, можно деструктурировать некоторые ключи карты следующим образом:

(let [{:keys [cpp js]} {:cpp 88 :js 90}] 
   (println js); 90
   (println cpp); 88
 )

Есть ли способ уничтожить все ключи карты?

Может быть, что-то вроде:

(let [{:all-the-keys} {:cpp 88 :js 90}] 
   (println js); 90
   (println cpp); 88
 )

Ответы [ 3 ]

24 голосов
/ 19 февраля 2012

Не совсем, и это не будет хорошей идеей.Представьте себе:

(let [{:all-the-keys} m]
  (foo bar))

Являются ли foo и bar глобальными?Местные жители?Ключи, которые вы должны извлечь из м?Что должен делать этот код, если m иногда содержит клавишу foo, а foo также является глобальной функцией?Иногда вы вызываете глобальную, а иногда вызываете функцию, хранящуюся в m?

Игнорируя технические проблемы (большинство из которых, вероятно, можно преодолеть), это действительно катастрофа для читаемости и предсказуемости.Просто объясните, какие ключи вы хотите извлечь;если вы часто хотите вытащить одни и те же десять клавиш, вы можете написать простой макрос типа (with-person p body), который упростит вам этот общий случай.

10 голосов
/ 25 июня 2012

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

(defmacro let-map [vars & forms]
  `(eval (list 'let (->> ~vars keys
                         (map (fn [sym#] [(-> sym# name symbol) (~vars sym#)]))
                         (apply concat) vec)
               '~(conj forms 'do))))

Это в основном преобразует карту {:cpp 88 :js 90} в форму привязки [cpp 88 js 90], затем создает привязку let вместе с выполнением некоторого eval-jitsu, чтобы убедиться, что это происходит во время выполнения.

(def test-map {:cpp 88 :js 90})
(let-map test-map
  (println js)
  (println cpp))
;=> 90
;=> 88
6 голосов
/ 19 февраля 2012

Вы можете написать макрос для этого (эффективно создав мини-DSL), но я не думаю, что это очень хорошая идея по следующим причинам:

  • Для созданияправильные литералы времени компиляции js и cpp, вам нужно будет деструктурировать карту во время компиляции.Это было бы весьма ограничением с точки зрения того, что вы могли бы сделать с ним (вы должны были бы указать ключи заранее, и это не могло бы использоваться, например, в функциях более высокого порядка)
  • Макросы, как правило, плохиеИдея, когда более простой метод сделает эту работу (см. ниже)

Я бы порекомендовал просто использовать дозыq в вашем случае для циклического перемещения по карте:

(let [my-map {:cpp 88 :js 90}]
  (doseq [[k v] my-map]
    (println v)))

Обратите внимание, что:

  • Вы можете использовать деструктурирование, как описано выше, чтобы извлечь ключ k и значение v из каждой записи карты
  • Я использовал доза вместо для , потому что он не ленивый, и в этом примере кажется, что вы используете цикл только для println побочных эффектов.
  • Если вместо этого вы хотите ленивую последовательность значений (88 90), тогда будет для .
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...