Clojure своп! расщепление атома - PullRequest
7 голосов
/ 20 января 2012

Есть ли более простой способ написать этот код в 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))

альтернативный способ написать это будет:

(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))

Это кажется еще хуже.

В любом случае, у меня есть код, который много использует атомы для постановки в очередь, и использование первого подхода делает код действительно запутанным, я ожидаю, что будет что-то вроде:

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

или какой-то подобный механизм в свопе! функция, так как кажется, что вы хотели бы делать это часто (даже не ограничиваясь очередями, я столкнулся с несколькими другими случаями использования, где было бы полезно вернуть другое значение, например, старое значение, которое было заменено вне), и это не сломает атом / обмен! семантика.

Есть ли способ сделать это в Clojure?

Ответы [ 2 ]

16 голосов
/ 20 января 2012
(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)
3 голосов
/ 14 апреля 2015

Использовать ref было бы проще:

(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))
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...