Are pipe dreams made of promises?

unsorted — cgrand, 18 November 2009 @ 19 h 32 min

follow-up: pipe dreams aren’t necessarily made of promises

(defn pipe
 "Returns a pair: a seq (the read end) and a function (the write end).
  The function can takes either no arguments to close the pipe 
  or one argument which is appended to the seq. Read is blocking."
 []
  (let [promises (atom (repeatedly promise))
        p (second @promises)]
    [(lazy-seq @p)
     (fn 
       ([] ;close the pipe
         (let [[a] (swap! promises #(vector (second %)))]
           (if a
             (deliver a nil)
             (throw (Exception. "Pipe already closed")))))
       ([x] ;enqueue x
         (let [[a b] (swap! promises next)]
           (if (and a b)
             (do
               (deliver a (cons x (lazy-seq @b)))
               x)
             (throw (Exception. "Pipe already closed"))))))]))

Beware of not printing the seq while the pipe is still open!

(let [[q f] (pipe)]
  (future (doseq [x q] (println x)) (println "that's all folks!"))
  (doseq [x (range 10)]
    (f x))
  (f)) ;close the pipe

9 Comments »

  1. Looks cool but I’m not sure what this is for.

    Comment by anonymous — 19 November 2009 @ 1 h 24 min
  2. @anonymous it creates a communication channel whose ends can then be handed to two different threads. The read end is a plain lazy seq.

    Comment by cgrand — 19 November 2009 @ 9 h 01 min
  3. Where we can read more about new developments in Clojure like promise/deliver?

    Comment by rkrastev — 19 November 2009 @ 10 h 41 min
  4. The function looks useful and the implementation very clever. However, I couldn’t quite wrap my head around the fact why you use “second” and “next” so quite often. Is this to force evaluation to move down the seq one step?

    Comment by dwerner — 30 December 2009 @ 20 h 04 min
  5. @dwerner

    I could be wrong but I’m pretty sure the call to second is required because when we enqueue we recursively shift along the unfulfilled promises with the call to (swap! promises next).

    If we handed the reader the very first item of promises then the reader would block forever because the delivery of a new list (made of the enqueued values cons’d with a lazy seq of the remaining promises) happens in the next cell.

    This does appear to mean that the very first promise is unfulfilled (and gc’d because nothing references it), but it means we need less logic in our enqueueing.

    I personally find this code to be incredibly elegant and concise… (Though it did take a while to figure out how it worked)

    Comment by Rick Moynihan — 23 February 2010 @ 14 h 06 min
  6. clojure.contrib.pipes? :)

    Comment by Greg — 18 March 2010 @ 20 h 38 min
  7. [...] of the spinning nature of atoms, it’s kind of a hack (a fun hack but still a hack) to build queues on it. Here is the same pipe function built on Java [...]

  8. My home is Texas now. However I’d like a school focusing on just that, or in theatre art type stuff (:

    Comment by foldable ladder — 28 April 2011 @ 0 h 43 min
  9. Youre so cool! I dont suppose Ive learn something like this before. So good to seek out someone with some authentic thoughts on this subject. realy thanks for starting this up. this web site is something that’s needed on the net, somebody with somewhat originality. useful job for bringing one thing new to the internet!

    Comment by cat tree — 2 May 2011 @ 5 h 59 min

RSS feed for comments on this post. TrackBack URI

Leave a comment

(c) 2012 Clojure and me | powered by WordPress with Barecity