Is(def m(update-in m ks f&args))a good practice?
问题描述:
我是新来到clojure的世界,我有疑问。 我有一个嵌套的地图,如Is(def m(update-in m ks f&args))a good practice?
(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}))
,但我有我做了错误的感觉方式...
答
如果您想更新它们,您需要将accounts
更改为可变。通常的做法是通过账户。那么你的功能可能是这样的:
(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
之内。如果您正在考虑在defn
内部输入def
,请改为使用let
。在defn
之外,可以使用def
来更新另一个具有不同名称的def
,因此(def m2 (update-in m1 ...))
将会很好。
+0
很好,谢谢您的回答。这是我第一次尝试,我正在考虑在第二次尝试中使用ref(同时进行交易和更新多个帐户) – Darakt
您可以使用{}替代散列图,如:{:XYZ {:balance ....}} –