From: Heinrich A. <apf...@qu...> - 2012-04-29 12:55:56
|
Dear list, as you probably know, I'm the author of the reactive-banana package, which is a library for functional reactive programming (FRP) which can be used with wxHaskell. As such, I would like to propose a few changes to wxHaskell which are informed by FRP. Of course, while my primary aim is to gain better interoperability with my library, I think and hope that my proposed changes are of independent benefit. Today, I would like discuss *composable events* and event handlers. In wxHaskell, event handlers are currently set with the on combinator. set button [ on command := doSomething ] Unfortunately, this approach has several problems that don't make it very composable: 1. Currently, setting an event handler will also *remove* any previous event handler. 2. The event handler may have have several curried parameters, or even none. I have found that the most composable approach to events is the following type type Event a = AddHandler a newtype AddHandler a = AddHandler { addHandler :: (a -> IO ()) -> IO (IO ()) } Example usage doSometing :: () -> IO () ... removeSomething <- addHandler (on command button) doSomething The idea is that Event a represents an event that carries data of type a . If the event does not carry any data, then a = () . The addHandler function registers an additional event handler with the event, while keeping the old handlers intact. The return value of addHandler can be used to remove the event handler again if desired. (This is how GTK does it, by the way.) With this type, we can easily define new events from old ones, for instance instance Functor AddHandler where fmap f e = AddHandler $ \g -> addHandler e (g . f) filterJust :: AddHandler (Maybe a) -> AddHandler a filterJust e = AddHandler $ \g -> addHandler e (maybe (return ()) g) -- mouse click event click :: AddHandler Point click = filterJust . fmap matchClick $ mouse where matchClick (MouseLeftDown pt _) = Just pt matchClick _ = Nothing Note that this only works well if the event data always given as a single type, not multiple curried arguments. I think this is very pleasant. In particular, it cleans up the confusion about the current crop of write-only events like click and motion . It also looks a bit like FRP, though it is not powerful emough to become "true" FRP for reasons I don't want to go into right now. The main drawback of the AddHandler approach is that we cannot keep the current syntax set button [ on click := .. ] since setting an event handler rightfully implies that the old event handlers are removed. I'm somewhat undecided about possible solutions, but we could introduce a new assignment symbol set button [ on click :+ .. ] that only works on events. What do you think? Best regards, Heinrich Apfelmus -- http://apfelmus.nfshost.com |