Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Update multiple elements of a Clojure atom within a single swap statement?

Tags:

clojure

I have an atom that has two parts to it.

(def thing (atom {:queue '() :map {}}))

I want to update both :queue and :map in one atomic stroke, to prevent them from getting off-sync.

Queue individually:

(swap! thing update-in [:queue] (list 1))

(From this question: How to append to a nested list in a Clojure atom?)

Map individually:

(swap! thing assoc-in [:map 1] (:key :value))

(From this question: Using swap to MERGE (append to) a nested map in a Clojure atom?)

How can I do these both within a single swap statement? (assuming that would prevent them from getting off-sync?)

like image 950
szxk Avatar asked Mar 10 '14 23:03

szxk


2 Answers

You have one change you want to make, right? And you could write that change as a pure function? All you need to do is write that function, and pass it as the argument to swap!.

(defn take-from-queue [{q :queue, m :map}]
  {:queue (rest q), :map (assoc m :new-task (first q))})

(swap! thing take-from-queue)

Where of course I have no idea what you actually want the body of your function to do, so I've made up something that doesn't throw an exception.

like image 196
amalloy Avatar answered Nov 12 '22 07:11

amalloy


Say you have a hash-map atom:

(def m1 (atom {:a "A" :b "B"})) 

To change :a and :b at the same time, changing their values to values that are different, say the numbers 1 and 2, use this function:

(defn my-swap! [params]
  (swap! m1 (fn [old new] new) params))

, like so:

(my-swap! {:a 1 :b 2}) ;=> {:a 1, :b 2}

And the same effect could be achieved with the following function and execution:

(defn my-multi-swap! [params1 params2]
  (swap! m1 (fn [old new1 new2] new2) params1 params2))

(my-multi-swap! {} {:a 1 :b 2}) ;=> {:a 1, :b 2}

Normally reset! is used if you want to ignore the old value. Here we use it:

(defn my-merge-swap! [params]
  (swap! m1 (fn [old new] (merge old new)) params))

(my-merge-swap! {:b 3}) ;=> {:a "A", :b 3}

The first parameter to the swap! function is the existing value of the atom, and you must pass in one or more extra parameters, which you can use to give the atom its new value.

like image 31
Chris Murphy Avatar answered Nov 12 '22 07:11

Chris Murphy