Обновить два значения одновременно в clojure

Мне интересно, как обновить два значения одновременно. Например, я хочу увеличить месяц и одновременно уменьшить возраст. Мой код

user=>(def users {:month 1 :age 26})
user=>(update-in users [:month :age] inc dec)

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

3 ответа

update не изменяет значение, оно просто возвращает новое значение, поэтому это просто функция. Если вам нужно обновить 2 поля карты, простой способ сделать это - просто позвонить update дважды, сначала на исходной карте, а затем на результате первого обновления:

(defn update-month-and-age [user]
  (update (update user :month inc) :age dec))

Который выглядит лучше, используя ->:

(defn update-month-and-age [user]
  (-> user
      (update :month inc)
      (update :age dec)))

В этом простом случае (обновление функций без дополнительных параметров) вы также можете сделать это следующим образом:

user> (def users {:month 1 :age 26 :records [1 2 3]})
#'user/users

user> (reduce-kv update users {:month inc :age dec :records reverse})
{:month 2, :age 25, :records (3 2 1)}

с дополнительными параметрами это будет немного более многословно:

user> (reduce-kv (partial apply update)
                 users
                 {:month [+ 2] :age [dec] :records [conj 101]})
{:month 3, :age 25, :records [1 2 3 101]}

ну, это еще хуже, чем простое использование потокового макроса.

Обычно я пытаюсь решить эту проблему, написав функцию, которая берет map: keyword -> function и выдает функцию, которая применяет все функции к соответствующим записям записи / карты.

Такая функция

(defn field-updater [fn-map]
  (fn [record]
    (reduce
     (fn [m [k f]] (assoc m k (f (m k))))
     record
     fn-map)))

И мы используем его для создания необходимого вам средства обновления полей:

(def update-in-users (field-updater {:month inc :age dec}))

... который мы можем применить

(update-in-users users)
;{:month 2, :age 25}
Другие вопросы по тегам