Clojure Swap! atom removal

Is there an easier way to write this code in Clojure:

(def queue (atom {:top nil :queue PersistentQueue/EMPTY})) (swap! queue #(hash-map :top nil :queue (conj (:queue %) "foo"))) (let [{:keys [top]} (swap! queue #(hash-map :top (peek (:queue %)) :queue (pop (:queue %))))] (println top)) 

Alternative recording method:

 (def queue (atom PersistentQueue/EMPTY)) (swap! queue conj "foo") (let [top (atom nil)] (swap! queue (fn [queue] (reset! top (peek queue)) (pop queue))) (println @top)) 

It seems even worse.

In any case, I have code that uses atoms for mass servicing, and using the previous approach makes the code really confusing, I expect there will be something like:

 (swap! queue (fn [queue] (AtomSwapResult. atom-value return-value)) 

or some kind of similar mechanism in a swap! because it looks like what you would like to do often (even without being limited to the queue, I hit several other use cases when it would be useful to return another value, for example, the old value that was replaced) and it does not break the atom / swap ! semantics.

Is there a way to do this in Clojure?

+7
source share
2 answers
 (defn dequeue! [queue] (loop [] (let [q @queue value (peek q) nq (pop q)] (if (compare-and-set! queue q nq) value (recur))))) (def queue (atom clojure.lang.PersistentQueue/EMPTY)) (swap! queue conj :foo) (swap! queue conj :bar) (seq @queue) (dequeue! queue) (seq @queue) 
+16
source

Using ref would be a simpler option:

 (defn dequeue! "Given a ref of PersistentQueue, pop the queue and change the queue" [queue-ref] (dosync (let [val (peek @queue-ref)] (alter queue-ref pop) val))) (let [q (ref clojure.lang.PersistentQueue/EMPTY)] (dosync (alter q conj 1 2 3) (alter q conj 5)) (fu/dequeue! q) => 1 (seq @q) => (2 3 4 5)) 
+3
source

Source: https://habr.com/ru/post/906460/


All Articles