Clojure交换!原子队列出局

Raf*_*tić 7 clojure

有没有更简单的方法在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))
Run Code Online (Sandbox Code Playgroud)

写它的另一种方法是:

(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))
Run Code Online (Sandbox Code Playgroud)

这似乎更糟糕.

无论如何,我有一个使用原子排队很多的代码,并使用前一种方法使代码真的令人困惑,我希望有类似的东西:

(swap! queue (fn [queue] (AtomSwapResult. atom-value return-value))
Run Code Online (Sandbox Code Playgroud)

或交换中的一些类似机制!函数,因为它似乎是你想要经常做的事情(甚至不限于排队,我已经遇到了几个其他用例,其中返回一个不同的值是有用的,例如,交换的旧值out)并且它不会打破原子/交换!语义.

有没有办法在Clojure中做到这一点?

kot*_*rak 16

(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)
Run Code Online (Sandbox Code Playgroud)