Using swap! to update the map vector in the atom Clojure (Script)

I have an atom containing a map vector (sample code from c2 library):

(def ^:export data
  (atom [{:metric "Revenue", :units "USD in thousands"
           :ranges [150 225 300], :measurements [220 270], :markers [250]}
          {:metric "Profit", :units "%"
           :ranges [20 25 30], :measurements [21 23], :markers [26]}
          {:metric "Order Size", :units "USD average"
           :ranges [350 500 600], :measurements [100 320], :markers [550]}
          {:metric "New Customers", :units "count"
           :ranges [1400 2000 2500],
           :measurements [1000 1650], :markers [2100]}
          {:metric "Satisfaction", :units "out of 5"
           :ranges [3.5 4.25 5], :measurements [3.2 4.7], :markers [4.4]}]))

I can easily change (well, make a modified copy) of this by increasing the value :markers, this way:

(map (fn [m] (update-in m [:markers] (fn [v]  (map inc v)))) @data)

In most cases, I am familiar with updating atoms with swap!, but the best I could do in this case is the following:

(defn upmark []
  (let [new (map (fn [m] (update-in m [:markers] (fn [v]  (map inc v)))) @data)]
    (vec (reset! data new))))

This is clearly bad, since I will reset the entire state of the atom instead of just updating the fragments I need. I'm just confused why it is so difficult to apply code that does the right thing for a regular map vector using swap!. I get that it swap!has an implicit apply, but I can not force the application fn correctly.

+4
1

. (swap!) , swap. , , , (swap!), :

(def ^:export data (atom ...))

(defn upmark [data]
    (mapv (fn [m] (update-in m [:markers] (fn [v]  (mapv inc v)))) data))

(swap! data upmark)

, (map) (mapv), .

+6

All Articles