reactive-banana
reactive-banana copied to clipboard
Pruning old `reactimate` calls
I'm using Reactive Banana with gi-gtk to build a GUI application. I want to create a widget in response to an event and have that widget respond to changes in a Behavior
and generate events for output. However I have a space-time leak from the interaction of reactimate
with execute
.
-- | Display the value in the behavior and emit events
-- in response to user actions.
makeMyWidget :: Behavior DisplayValue -> MomentIO (Widget, Event Edit)
-- | Extract data specified by Foo into DisplayValue
getDisplay :: Foo -> AppState -> DisplayValue
triggerEvent :: Event Foo -- The event that causes the widget to appear.
globalState :: Behavior AppState
-- | Add the argument to the GUI widget tree, dstroying any previous one.
showWidgetInGui :: Widget -> IO ()
So now I can write this:
runDisplays :: MomentIO (Event Edit)
displays <- execute $
makeMyWidget (\f -> getDisplay f <$> globalState) <$> triggerEvent
reactimate $ showWidgetInGui . fst <$> displays
switchE $ snd <$> displays
This seems to work fine. Every time the triggerEvent
happens a new window pops up containing data extracted from globalState
.
However when I trace the execution of getDisplay
I see it being run for every past invocation as well as the one currently displayed. Presumably this is because the makeMyWidget
includes reactimate'
calls to update its display from the input behavior.
execute
allows me to dynamically add processing to the event network, but I can't see any way of dynamically pruning old processing that is no longer needed.
I'm thinking of an API along the following lines:
-- | A reference to an existing "reactimate"
data Cookie
-- | The same as the existing function, but returning a cookie.
reactimate :: Event (IO ()) -> MomentIO (Cookie)
-- | Dynamically remove a reactimate from the network.
stopReactimate :: Cookie -> IO ()
With this I could put a bunch of reactimate
calls inside an execute
, collect all their cookies, and then have the corresponding stopReactimate
calls as a callback from the destruction of the widget that they were updating. Having stopReactimate
in the IO monad makes it easy to put in a callback like this. The data structures associated with the reactimate
should also be cleared or dropped to allow the widget to be garbage collected along with everthing else.
I've put in pull request #199 for an extension similar to what I described above.