编辑:
dosync
创建一个函数,因此对recur
的调用将被解释为对生成的函数dosync
的调用。
这是我实际制作的功能的足迹。我认为保持尽可能简单。
(defn change-to-ref [ref data]
(dosync
(if-let [[new-ref new-data] (some-test @ref data)]
(recur new-ref new-data)
(alter ref f data))))
例外:
CompilerException java.lang.IllegalArgumentException:
Mismatched argument count to recur, expected: 0 args, got: 2
ORIGINAL:
我试图更新ref中的hashmap,如下所示
(def example-ref (ref {:some {:nested {:structure}}}))
(defn f [this] [this]) ;; just an example function
(sync (alter example-ref update-in [:some] f)
user=> nil
因为它应该返回
,这是非常令人惊讶的user=> {:some [{:nested {:structure}}]}
比我尝试过:
(update-in @example-ref [:some] f)
user=> {:some [{:nested {:structure}}]}
但是,我读到alter
调用apply
所以:
(apply update-in @example-ref '([:some] f))
user=> {:some nil}
好的,让我们以正确的方式做到:
(apply update-in @example-ref (list [:some] f))
user=> {:some [{:nested {:structure}}]}
很好,我想到这一点,
但它没有解释为什么alter
出错了
我甚至无法改变它......
(apply (fn [a b] (update-in a b f)) @example-ref '([:something]))
user=> {:some [{:nested {:structure}}]}
它看起来很糟糕,但至少它可以工作,我可以模拟它alter
:D
(sync (alter example-ref (fn [a b] (update-in a b f)) [:some])
user=> nil
好的,你赢了。
我看了看:
clojure.lang.Ref.alter source
但是没有变得更聪明。 (根据我的理解,alter
实际上不会调用apply
)
我希望你们中的一些人能够理解这一点并得到关于正确代码的答案。
答案 0 :(得分:0)
问题是sync
的签名如下:
(sync flags-ignored-for-now& body)
忽略此宏的第一个参数。此外,文档建议为其传递nil
:
transaction-flags => TBD,暂时没有通过
因此,使用sync
的正确方法是:
> (sync nil (alter example-ref update-in [:some] (partial conj [])))
{:some [{:nested {:structure :foo}}]}
我还建议使用dosync
代替sync
(只是不要弄乱第一个参数;本质上是这些函数are the same):
> (dosync (alter example-ref update-in [:some] (partial conj [])))
{:some [{:nested {:structure :foo}}]}