
I've been worrying about what happens when monads end up caught inside an Event stream, as they inevitably do. Usually this is the IO monad, & usually it's not a problem because adaptE deals with Event (IO a) types eventually. But look at the following (contrived) example: I read lots of people's mail. I have a load of buttons which add a person's mail to the set I receive, summarised by: addPerson :: Event Person I want an event of all the mail I get. Given: getMail :: Person -> Event Mail I can do: allMail :: Event Mail allMail = addPerson >>= getMail But realistically, I might have to create a new event for each person, or look the event up in a database or something. Then I have only: getMailM :: Person -> IO (Event Mail) So, fmap getMailM addPerson :: Event (IO (Event Mail)) and there is no longer a function (like "join" above) for getting an Event Mail, an Event (IO Mail), an IO (Event Mail) or even an IO (Event (IO Mail)) out of that as things stand. Given a clock, I could do something like:-- undoIO :: Clock t -> Event (IO a) -> IO (Event a) undoIO c e = do (sink, e') <- makeEvent c forkIO $ adaptE (>>= sink) e return e' But having a clock lying around seems wrong; and I'd ideally like the new Event to be simultaneous with the old one (provided getMailM finishes quickly). I could also do this an old-fashioned way by passing around event sinks; but again that's not really in the spirit. Also, these fixes will only stand a chance with IO (or ST, maybe); what if getMailM :: Person -> State Foo (Event Mail) ? So, can a function be constructed with the desired type (say Event (m (Event a)) -> m (Event a)), or is that unreasonable to expect? Is there a (generalizable) alternative way of doing this example which doesn't require one? This seems a natural thing to want to do. Freddie Manners