Является ли (def m (update-in m ks f & args)) хорошей практикой?
Я новичок в мире clojure и у меня есть сомнения. У меня есть вложенная карта, такая как
(def accounts (hash-map :XYZ (hash-map :balance (hash-map 171000 0 :171018 500 :171025 200)
:statement (hash-map :171018 [{:desc "purchase" :amount 200}
{:desc "deposit" :amount 700}]
:171025 [{:desc "purchase" :amount 300}]))
И я хочу обновить утверждения, поэтому я написал простую функцию:
(defn add-statement
[account date desc amount]
(def accounts (update-in accounts [account :statement date] conj {:desc desc :amount amount}))
Но у меня такое чувство, что я делаю это неправильно...
1 ответ
Вам нужно будет изменить accounts
быть изменчивым, если вы хотите обновить их. Обычный способ сделать это, делая учетные записи atom
, Тогда ваша функция может выглядеть так:
(defn add-statement! [account date desc amount]
(swap! accounts update-in [account :statement date]
(fn [line-items]
(conj (or line-items []) {:desc desc :amount amount}))))
Это добавит позицию выписки на новую или существующую дату. update-in
такой же, как у вас, за исключением того, что позиция для новой даты будет помещена в вектор, а не в список. (conj
сохраняет тип, но он должен знать тип: (conj nil :a)
дает (:a)
).
Чтобы превратить счета в атом:
(def accounts (atom (hash-map ...)))
Я замечаю, что ваши остатки не верны в любом случае. Но если вы обновляете их, обязательно сделайте это в том же swap!
функция.
Чтобы ответить на ваш вопрос "Есть (def m (update-in m ...))
хорошая практика?". Определенно не внутри defn
, Если вы думаете поставить def
внутри defn
использовать let
вместо. Вне defn
было бы хорошо иметь def
что обновляет другой def
это имеет другое имя, так что (def m2 (update-in m1 ...))
,