Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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?

like image 291
Stephen Morgan Avatar asked Nov 08 '22 11:11

Stephen Morgan


1 Answers

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.

like image 74
Stephen Morgan Avatar answered Dec 09 '22 11:12

Stephen Morgan