I am reading Conal Elliot's paper "Declarative Event-Oriented Programming" which has its examples written using a Fran library which is now obsolete.
As I am learning FRP I try to implement those examples using reactive-banana. I seem to have no problem with this (but have to think a lot :)). The only thing I do not understand is how to correctly translate Fran's ifB.
It seems to have this type signature:
ifB :: Behavior Bool -> Behavior a -> Behavior a -> Behavior a
But reactive-banana only has switchB for this sort of thing.
Currently I managed to do it by adding an additional "trigger" event which will be used to switch behaviors, like this:
ifB :: MonadMoment m => Event b -> BoolB -> Behavior a -> Behavior a -> m (Behavior a)
ifB trigger condB b1 b2 = switchB b2 (switcherB <@ trigger)
where switcherB = (\x -> if x then b1 else b2) <$> condB
I am not sure if this is a correct and good solution. Is it performant?
Below is a snippet from the paper which uses ifB:
editCPoint :: User -> S.Point2 -> CPoint
editCPoint u p0 = (pos, closeEnough)
where
pos, lastRelease :: Point2B
-- vvv this is the ifB in question!
pos = ifB grabbing (mouse u) lastRelease
lastRelease = stepper p0 (release ‘snapshot_‘ pos)
closeEnough, grabbing :: BoolB
closeEnough = distance2 pos (mouse u) <* grabDistance
grabbing = stepper False (grab -=> True .|. release -=> False)
grab, release :: Event ()
grab = lbp u ‘whenE‘ closeEnough
release = lbr u ‘whenE‘ grabbing
grabDistance :: RealB
grabDistance = 2 * pointSize
I managed to get this snippet working with reactive-banana, by using my implementation of ifB and feeding it a cursor move event so it gets updated regularly. I tried to feed it only mouse press/release events as triggers for switching and it didn't work correctly...
Did I do it wrong? Any advice on how to do better?
Behaviorhas anApplicativeinstance, which is enough to implementifBwithout dynamic switching:Or, using
boolfromData.Bool: