[英]Clojure alter update-in returns nil and dosync doesnt allow recur
EDIT: 编辑:
dosync
creates itself a function so calls to recur
get interpreted as calls made to the function dosync
generated. dosync
创建自身的函数调用,从而对recur
得到解释为对函数的调用dosync
产生。
This is the footprint of the function I actually made. 这是我实际制作的功能的足迹。 Kept it as simple as possible, I think.
我认为,请保持尽可能简单。
(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))))
The Exception: 例外:
CompilerException java.lang.IllegalArgumentException:
Mismatched argument count to recur, expected: 0 args, got: 2
ORIGINAL: 原版的:
I was trying to update a hashmap in a ref as follows 我试图按如下方式更新ref中的哈希图
(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
Which was quite surprising as it should've returned 令人惊讶的是它应该回来了
user=> {:some [{:nested {:structure}}]}
So than I tried: 所以比我尝试的:
(update-in @example-ref [:some] f)
user=> {:some [{:nested {:structure}}]}
But than I read that alter
calls apply
so: 但比起我所读到的那样,
alter
call apply
:
(apply update-in @example-ref '([:some] f))
user=> {:some nil}
Okay, so lets do it the proper way: 好的,让我们以正确的方式来做:
(apply update-in @example-ref (list [:some] f))
user=> {:some [{:nested {:structure}}]}
Well it's great I figured this out, but it doesn't explain why this goes wrong in alter
and I can't even change it anyways... 好吧,我很清楚这一点,但是并不能解释为什么这会在
alter
出错,而且我什至无法更改它...
(apply (fn [a b] (update-in a b f)) @example-ref '([:something]))
user=> {:some [{:nested {:structure}}]}
It looks terrible but atleast it works and I can simulate it for alter
:D 它看起来很糟糕,但至少可以正常工作,我可以为
alter
:D 模拟它
(sync (alter example-ref (fn [a b] (update-in a b f)) [:some])
user=> nil
Ok, you win. 好吧,你赢了。
I took a look at: clojure.lang.Ref.alter source but have grown none the wiser. 我看了一下: clojure.lang.Ref.alter的源代码,但没有一个更明智。 (other than, that to my understanding,
alter
actually doesn't call apply
) (除了,据我所知,
alter
实际上并不apply
)
I hope some of you will understand this and have an answer as to what is the proper code. 我希望你们中的一些人能理解这一点,并对正确的代码有一个答案。
The problem is that signature of sync
is as follows: 问题是
sync
签名如下:
(sync flags-ignored-for-now & body)
(现在忽略同步标记和正文)
First argument of this macro is ignored. 该宏的第一个参数被忽略。 Also documentation recommends to pass
nil
for it: 此外,文档建议为此传递
nil
:
transaction-flags => TBD, pass nil for now
transaction-flags => TBD,暂时传递nil
So, correct way of using sync
would be: 因此,使用
sync
正确方法是:
> (sync nil (alter example-ref update-in [:some] (partial conj [])))
{:some [{:nested {:structure :foo}}]}
I'd also recommend to use dosync
instead of sync
(just not to mess with the first parameter; essentially these functions are the same ): 我还建议使用
dosync
而不是sync
(只是为了避免与第一个参数dosync
;本质上,这些函数是相同的 ):
> (dosync (alter example-ref update-in [:some] (partial conj [])))
{:some [{:nested {:structure :foo}}]}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.