Search code examples
haskellfrpreactive-banana

How to transform events with an IO function?


Let's say I have

e1 :: Event t A
f  :: A -> IO B

I want to create

e2 :: Event t B

which is triggered by e1, and whose values are determined by executing f on the value of e1 at the time of the event occurrence.

I see two potential ways to do this, via dynamic event switching and using handlers, but they both look too complicated for such a simple thing.

What is the proper way to do this?


Solution

  • Since the function f has a side effect, this is actually not a simple thing to do. The main reason is that the order of side effects is not well-defined when there are multiple simultaneous events. More generally, I was unable to conceive a good semantics for dealing with IO actions in events. Consequently, reactive-banana does not provide a pure combinator for this situation.

    If you want to do this anyway, you have to use a more elaborate mechanism that also determines the order of side effects. For instance, you can use reactimate and write a combinator

    mapIO :: Frameworks t => (a -> IO b) -> Event t a -> Moment t (Event t b)
    mapIO f e1 = do
        (e2, fire2) <- liftIO newAddHandler
        reactimate $ (\x -> f x >>= fire2) <$> e1
        fromAddHandler e2
    

    However, note that this may give unexpected results as the result event e2 is no longer simultaneous with the input event e1. For instance, behaviors may have changed and other side effects may have been executed.