统一更新模型是 API 约定,其中各种引用类型的对象可以以一致的方式更新,尽管具有专门的功能:
;; Atoms
(swap! the-atom f …)
;; Agents
(send the-agent f …)
(send-off the-agent f …)
;; send-via takes an additional initial argument, but otherwise
;; follows the same convention (and of course it's an exact match
;; when partially applied – (partial send-via some-executor))
(send-via executor the-agent f …)
;; Refs
(dosync
(alter the-ref f …)
(commute the-ref f…))
在每种情况下,f 是应该用于更新 Atom / Agent / Ref 持有的值的函数,… 是附加参数,如果有的话(例如(swap! the-atom f 1 2 3)),以及调用是引用将自动假定值(f old-value …) - 尽管关于swap! / alter / send / ... 调用的确切时间取决于所讨论的引用类型和使用的更新函数.
这是一个例子:
(def a (atom 0))
(swap! a - 5)
@a
;= -5
Var 通常不打算用于可能使用上述引用类型的相同目的,但它们也具有具有相同合约的更新功能:
(alter-var-root #'the-var f …)
最后,update 和 update-in 函数在这方面值得一提;实际上,它们将统一更新模型约定扩展到值——当然,值是不可变的,因此调用update 或update-in 不会导致任何对象明显更改,但返回值的生成与将更新函数应用于预先存在的值和可能的一些额外参数的结果类似:
(update {:foo 1} :foo inc)
;= {:foo 2}
在 UUM 更新调用的上下文中,问题中引用的 fixing 函数比 fix(在同一命名空间中定义)效果更好,因为它可以以与 UUM 更新方式相吻合的方式传递多个参数像swap! 这样的函数可以工作,而fix 你必须使用匿名函数:
;; the example from the docstring of fixing
(swap! my-atom fixing map? update-in [k] inc)
;; modified to use fix
(swap! my-atom fix map? #(update-in % [k] inc))