简体   繁体   English

Clojure alter update-in返回nil,而dosync不允许递归

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM