是(def m(update-in m ks f& args))一个好习惯吗?

时间:2017-10-28 22:10:48

标签: clojure update-in

我是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 个答案:

答案 0 :(得分:2)

如果要更新它们,则需要将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 ...))