haskellfrpreflex

Reflex: Create a resettable delayed event


I'm using Reflex within Haskell, and am trying to create an event which fires (for question purposes) a set period of time after another, let's say 2 seconds. However, the counter should reset whenever the original event fires, so that if the original event fires twice 1 second apart, there should only be one firing of the second event: 2 seconds after the last original event.

I've managed to implement this behaviour with

delayedReset :: MonadWidget t m => Event t () -> m (Event t ())
delayedReset ev = fmap (switch . current) . widgetHold (return never) $ timer <$ ev
  where
    timer = delay 2 =<< getPostBuild

but it seems overkill to use widgetHold; it seems that we should only really need a MonadHold constraint. Is there a more idiomatic way to write this function?


Solution

  • It seems that I missed the rather obvious:

    delayedReset :: MonadWidget t m => Event t () -> m (Event t ())
    delayedReset ev = do
        endEv <- delay 2 ev
        countDyn <- foldDyn ($) (0 :: Int) $ leftmost
          [ (+1) <$ ev, subtract 1 <$ endEv ]
        return $ attachPromptlyDynWithMaybe ifZero countDyn endEv
      where
        ifZero 0 a = Just a
        ifZero _ _ = Nothing
    

    The constraints can be relaxed, though this makes them much more verbose.

    In the end, though, I went with my first solution. I think the performance hit is minor enough and it simplifies some other aspects of the program.