EDIT:
dosync
creates itself a function so calls to recur
get interpreted as calls made to the function dosync
generated.
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
(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:
(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...
(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
(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. (other than, that to my understanding, alter
actually doesn't call apply
)
I hope some of you will understand this and have an answer as to what is the proper code.