Reputation: 33
I'm new to clojure, and i need to update two values inside this atom:
(def app-state (atom {:id "1":status 0 :st 0}))
Im using the following:
(let [value (mod (+ (:st @app-state) 1) 4)]
(swap! app-state update-in [:status] value)
(swap! app-state update-in [:st] inc))
Im getting:
Caused by: java.lang.ClassCastException: java.lang.Long cannot be cast to clojure.lang.IFn
Upvotes: 3
Views: 2639
Reputation: 31
Below is a repl session based on your problem. First I define app-state
exactly as you posted. Next, I define bump-state
as an anonymous function #(…)
that takes one argument, the current value of app-state
, denoted by the %
placeholder. The let
form binds the incremented value of the :st
key to st
. Finally, assoc
returns a new immutable map by associating new values with :st
and :status
of the previous map.
The next several lines just call swap!
to confirm that bump-state
works. The last line just defines the anonymous function directly in the call to swap!
. While the accepted answer works fine, I think this is a little more succinct.
user=> (def app-state (atom {:id "1":status 0 :st 0}))
#'user/app-state
user=> (def bump-state #(let [st (inc (:st %))] (assoc % :st st :status (mod st 4))))
#'user/bump-state
user=> (swap! app-state bump-state)
{:id "1", :status 1, :st 1}
user=> (swap! app-state bump-state)
{:id "1", :status 2, :st 2}
user=> (swap! app-state bump-state)
{:id "1", :status 3, :st 3}
user=> (swap! app-state bump-state)
{:id "1", :status 0, :st 4}
user=> (swap! app-state #(let [st (inc (:st %))] (assoc % :st st :status (mod st 4))))
{:id "1", :status 1, :st 5}
The whole idea of swap!
is that your update function operates on the current immutable value held by the atom and returns a new immutable value to replace it with. Your update function is simply a pure function, which lets you reason about it more easily and also play with it at the repl, just like other functions.
Upvotes: 3
Reputation: 144206
The third argument to update-in
takes a function but you are supplying a long (value
) which is why you get an exception. You could use assoc-in
instead which takes the value to associate in the map directly:
(swap! app-state assoc-in [:status] value)
However you should do the entire update to the state atomically within the function passed to swap!
e.g.
(swap! app-state (fn [{:keys [st] :as state}]
(let [st-next (inc st)
value (mod st-next 4)]
(merge state {:st st-next
:status value}))))
Upvotes: 5