
Hello, I've been having a little trouble writing a module that waits for and handles IO events, e.g. by reading from a pipe. It seemed natural to use some form of callbacks here, though that may very well be the wrong approach. I'd be happy to hear of alternatives. Anyway, I got a callback-based approach to work to some extent, but am not happy with the callback's type. The abstract form of this module is as follows. I'd appreciate any input. A class that specifies what we expect of the base monad.
class (Monad m) => MonadReq m
A class that specifies what we provide to the callback.
class (Monad m) => MonadProv m
The module's main function.
f :: (MonadReq m) => Callback m a -> m a f c = ...
Internally, we wrap the base monad with some monad transformer, say
data InternalT m a = ... with instance MonadTrans InternalT so that the callback can access the base monad, and instance (MonadReq m) => MonadProv (InternalT m) so that we can actually provide MonadProv.
A type for callback that works is
type Callback m a = InternalT m a What I don't like about this is that we shouldn't really need to expose what exact monad transformer we use. Also, if we added a second function that also runs the callback in a MonadProv but that uses a different transformer (for instance, needing to keep track of some extra state), we'd need a new callback type.
What seems to be the right type is
type Callback m a = forall t. (MonadTrans t, MonadProv (t m)) => t m a which sort of works with '-fglasgow-exts' (what's this extension called?). However, it seems to cause all kinds of problems, e.g. pairs of this type appear to be illegal.
Cheers Robert

Robert Vollmert writes: | Hello, | | I've been having a little trouble writing a module that waits for and | handles IO events, e.g. by reading from a pipe. It seemed natural to | use some form of callbacks here, though that may very well be the | wrong approach. I'd be happy to hear of alternatives. | | Anyway, I got a callback-based approach to work to some extent, but | am not happy with the callback's type. : Can the event and handler inhabit the same monad, say IO? If so, is the following the sort of thing you had in mind? waitAndHandleOneEvent :: IO e -> (e -> IO ()) -> IO () waitAndHandleOneEvent ioe h = forkIO (do e <- ioe h e) But then, because ioe and h always get combined the same way (ioe >>= h), we can generalise waitAndHandleOneEvent to waitAndDoOneThing :: IO () -> IO () waitAndDoOneThing io = forkIO io which is equivalent to using forkIO directly, as in do ... let ioe :: IO MyEvent ioe = ... h :: MyEvent -> IO () h e = ... forkIO (ioe >>= h) ... HTH. Tom

Tom Pledger wrote:
Robert Vollmert writes: | I've been having a little trouble writing a module that waits for and | handles IO events, e.g. by reading from a pipe. It seemed natural to | use some form of callbacks here, though that may very well be the | wrong approach. I'd be happy to hear of alternatives.
Can the event and handler inhabit the same monad, say IO? If so, is the following the sort of thing you had in mind?
waitAndHandleOneEvent :: IO e -> (e -> IO ()) -> IO () waitAndHandleOneEvent ioe h = forkIO (do e <- ioe h e)
Thanks for your reply. I was really hoping to do this without concurrency, though. Also, since I'd like to keep some extra state in the event loop, I'd like to be able to extend the monad. I'll try to clarify: I'd like to yield control to an IO action, which would run the callback on receiving an event. Like: handleEvents :: (Event -> IO ()) -> IO () handleEvents callback = do e <- getEvent callback e handleEvents callback However, I'd like to * not require IO, but any MonadIO (this shouldn't be a problem, I think) * extend the base monad in my event loop (no problem either) and * allow the callback to access this (which is where it gets difficult) In the case of reading events from a pipe, the extension in b) might consist of storing a handle to the pipe. Then, maybe I'd want to provide (in the extended monad) an action closePipe, which I'd like the callback to be able to call. Cheers Robert
participants (2)
-
Robert Vollmert
-
Tom Pledger