Based on my previous question whose setting I refined gradually (How to create monadic behaviour in reactive-banana):
Suppose there is eKey, an event fired whenever a key is pressed, b of type Buffer which is modified appropriately whenever a supported event occurs in eKey, and finally there are IO actions to be taken on some of the events. These IO actions depend on the state of b (for simplicity assume they print the current state of b to the console).
Currently, I have this to select the action that happens on an event:
getKeyAction :: KeyVal -> Maybe (IO Buffer -> IO Buffer)
getKeyAction 65288 = Just . liftM $ backspace
getKeyAction 65293 = Just $ \mb -> do
b <- mb
print $ "PRESSED ENTER: " ++ toString b
return emptyBuffer
getKeyAction 65360 = Just . liftM $ leftMost
getKeyAction 65361 = Just . liftM $ left
...
getKeyAction _ = Nothing
and then I do:
let
eBufferActions = filterJust $ getKeyAction <$> eKey
bBuffer = accumB (return emptyBuffer) eBufferActions -- model `b`
eBuffer <- changes bBuffer
reactimate' $ fmap displayBuffer <$> eBuffer
for some displayBuffer :: IO Buffer -> IO ().
It does not seem to work as intended. The state of bBuffer seems to be evaluated on every event anew (effectively running all IO actions collected thus far every time an event occurs) which makes sense when I think about it in retrospect.
How should I refactor my code to do this correctly? (i.e. IO actions see current state of the buffer, nothing except the buffer gets accumulated)
If I could construct an Event that bears value of the bBuffer on occasion of an appropriate eKey event, then I could simply map my a dedicated IO action over it and reactimate. What do you think? How to do that? Would <@ achieve what I am trying to do? But how would I postpone the current change to b associated with the current key press after I take snapshot of b with <@ to map the Buffer -> IO () over it?
OK, so I believe this solves my problem, but I am not sure it is the right thing to do. So please comment.
IO(other thanreturn)eKeyevent into two:eBufferandeConfirmeBuffercollects all modifying events (including clearing the buffer on confirmation)eConfirmcollects all confirmation eventseConfirmwith values ofbBuffer, which captures the evolution of the bufferreactimateseparately theIOand thechangesof the bufferThe code fragment:
Then in the description of the network:
for
evalBuffer :: Buffer -> IO ()anddisplayBuffer :: Buffer -> IO ().