What is the idiomatic way to pop a PersistentQueue in a ref?
Given a PersistentQueue in a ref:
(def pq (ref clojure.lang.PersistentQueue/EMPTY))
What is the idiomatic way to pop the queue and get the result?
My best attempt for your critique:
(defn qpop [queue-ref]
(dosync
(let [item (peek @queue-ref)]
(alter queue-ref pop)
item))
alter returns the in-transaction value of the queue which is popped already, so you can开发者_C百科't just do the alter by itself.
I can't think of something more idiomatic short of abstracting the body of your dosync away.
However if you are in for a stunt, you can try the off-by-one hack: always consider the head of the PQ as garbage (it contains the previously popped item). It follows that you can rewrite qpop
:
(defn qpop [queue-ref]
(peek (alter queue-ref pop))
It incurs adding special checks for emptiness (in particular when you conj). It also means keeping a reference to the item around for longer than it should (however if you look at the impl of PQ you'll see that by itsef it may keep references to popped items for too long, so liveness is already murky).
I used this hack here.
Your dosync body could be simplified using Common Lisp's prog1 macro, although core Clojure seems to lack it. There is a straightforward implementation on the Google group, along with some discussion on how you can make it a function (instead of a macro) in Clojure.
精彩评论