clojure event handling

45 views
Skip to first unread message

nchubrich

unread,
Nov 11, 2009, 7:22:40 PM11/11/09
to Clojure
I'm curious what the best idiomatic way of handling events is (e.g.
receiving a series of messages and dispatching functions on the basis
of the messages). One could use the 'experimental' add-watch(er)
functions. But it might also be nice to do something stream-oriented,
e.g. a doseq on a stream of events. But the trouble is this dies as
soon as the events stop arriving. Can event seqs be 'kept alive'
somehow (preferably without blocking)?
This seems like a pretty basic capability, so I figured it was
worth provoking discussion about.

Nick.

Alex Osborne

unread,
Nov 11, 2009, 8:14:04 PM11/11/09
to clo...@googlegroups.com
nchubrich wrote:
> I'm curious what the best idiomatic way of handling events is (e.g.
> receiving a series of messages and dispatching functions on the basis
> of the messages). One could use the 'experimental' add-watch(er)
> functions. But it might also be nice to do something stream-oriented,
> e.g. a doseq on a stream of events. But the trouble is this dies as
> soon as the events stop arriving. Can event seqs be 'kept alive'
> somehow (preferably without blocking)?

I may be misunderstanding what you mean by events but what about just
using an agent and a multi-method?

(defmulti handle-event (fn [state event] (:type event)))
(defmethod handle-event :party [state event]
(assoc state :status :dancing))
(defmethod handle-event :explosion [state event]
(assoc state :status :cowering))

(def my-agent (agent {}))

(send my-agent handle-event {:type :party, :location :your-house})

@my-agent => {:status :dancing}

Jeff Rose

unread,
Nov 12, 2009, 4:48:53 AM11/12/09
to Clojure
I think the typical way to handle this currently is by using a typical
handler function that is called whenever an event is fired. If the
events will be long running then you can use agents or a thread pool
(executor framework). If you need to dispatch events to other
handlers then use multi-methods.

It seems that what you are really asking for though, is a way to treat
a stream of events as a sequence. This is what they recently
introduced in .net land, with the RX framework:

http://www.leading-edge-dev.de/?p=501

Given that clojure has a nice library of sequence manipulation and
predicate functions, I think doing something similar could be useful.
I don't have a clear sense for how it would work though. You could
form a pipeline of sequence processing functions that get called
whenever a new event is fired, maybe by using a promise that gets
fulfilled when the event hits the pipeline?

-Jeff

Kevin Downey

unread,
Nov 12, 2009, 5:17:14 AM11/12/09
to clo...@googlegroups.com
http://paste.lisp.org/display/87611#2

"infinite seq of swing events"
> --
> You received this message because you are subscribed to the Google
> Groups "Clojure" group.
> To post to this group, send email to clo...@googlegroups.com
> Note that posts from new members are moderated - please be patient with your first post.
> To unsubscribe from this group, send email to
> clojure+u...@googlegroups.com
> For more options, visit this group at
> http://groups.google.com/group/clojure?hl=en



--
And what is good, Phaedrus,
And what is not good—
Need we ask anyone to tell us these things?

nchubrich

unread,
Nov 15, 2009, 2:41:49 PM11/15/09
to Clojure
Thanks for posting these examples; I'd never thought of using
multimethods that way. And thanks for the Swing example.
I'm really interested in functional-reactive programming; hope we
see lots of that stuff in Clojure. Anyone ever used FrTime in PLT?
Here's the Swing events without the Swing. Didn't know you could
override deref and invoke like that....

(import
'(java.util.concurrent LinkedBlockingQueue)
'(clojure.lang IDeref IFn))


(defn hydra
"returns a BlockingQueue, will return a new infinite lazy-seq
wrapped in a delay
evertime it is deref'ed. all items put in the LinkedBlockingQueue
will be added to
all the lazy-seqs producded by deref'ing"
[]
(let [consumers (atom nil)
producer (proxy [LinkedBlockingQueue IDeref IFn] []
(invoke [& x]
(doseq [y x] (.put this y)))
(deref []
(let [x (LinkedBlockingQueue.)]
(swap! consumers conj x)
(delay (repeatedly #(.take x))))))]
(future
(while true
(let [x (.take producer)]
(doseq [y @consumers]
(.put y x)))))
producer))

(def queue (hydra))

;see it working
(def results (atom nil))

(def show (fn [] (.start (Thread. (fn [] (doseq [i (force
@queue)] ;derefing the lbq from hydra returns a delay wrapped lazy-seq
(swap! results conj i)))))))
Reply all
Reply to author
Forward
0 new messages