Dealing with the current time in reactive-banana - haskell

How do you deal with the current time in reactive-banana?
Ideally I'd like to have a Behaviour which I can "poll" to get the current time. However, polling Behaviours with Events (via <# etc.) gives me the value of the Behaviour from the previous Event, not the current value. (I realise this is to avoid cyclic definitions which is indeed useful.)
I found fromPoll which I thought would help. Behaviours that are observed from fromPoll cannot depend on themselves, thus no cycles can be introduced by observing the behaviour just before this Event is fired rather than just after the previous Event fired.
A digression
In somewhat more formal terms I am suggesting that Events always occur at time t+ and Behaviours are always observed at time t- i.e. Events observe behaviours that happen an infinitessimally short time before them. New values of Behaviours generated by accumB and friends would always start from time t+ so could not be observed by Events which also happen at time t+.
Under this proposed semantics Behaviours created by fromPoll would be updated just before each Event is processed. Other Behaviours would be updated afterwards because they are created by accumB and friends.
My use case
Anyway, that's a significant digression to my main question. I want to know if there's some way to deal with current time (not the time of the previous Event) in reactive-banana. My use case is, for example, to keep track of the pings that entities send and if any of them hasn't sent a ping in a particular time interval to signal a warning event.
Of course I can and will fire off events very frequently, so my warnings won't be incorrect by a large amount. However it does seem to be a wart that they cannot be precise.
What's the right way of dealing with this?

Given your example use case, I think you should be fine if you stay away from fromPoll. To explain why, a few clarifications are needed. (Note: in what follows, "stream" refers to an Event t a, and "occurrence" to one of the firings which compose them.)
However, polling Behaviours with Events (via <# etc.) gives me the value of the Behaviour from the previous Event, not the current value.
I suppose you are alluding to explanations such as this one, from the docs for stepper:
Note that the smaller-than-sign in the comparision timex < time means that the value of the behavior changes "slightly after" the event occurrences. This allows for recursive definitions.
That delay, however, is only with respect to the stream used to define the behaviour (i.e. the one you pass to stepper/accumB) and any streams that are synchronised with it. For instance, suppose you have two independent streams, eTick and eTock, and the following network snippet:
eIncrement = (+1) <$ eTick
bCount = accumB 0 eIncrement
eCountTick = bCount <# eTick
eCountTock = bCount <# eTock
eIncrement and eCountTick are in sync with eTick, and so the value observed through eCountTick is the "old" value; that is, the value before the synchronised update. From the point of view given by eCountTock, however, none of that matters. To an observer using eCountTock, there is no delay to speak of, and the value is always the current one.
Behaviours that are observed from fromPoll cannot depend on themselves, thus no cycles can be introduced by observing the behaviour just before this Event is fired rather than just after the previous Event fired.
We are only concerned with streams synchronised with the one which updates the behaviour. Thus, as far as observed values go "just before the next occurrence" and "just after the previous occurrence" boil down to the same thing. fromPoll, however, muddles things quite a bit. It creates a behaviour which is updated whenever any occurrence happens in the event network; and so the updates are synchronised with the union of all streams. There is no such thing as a stream independent from a fromPoll event, and therefore the observed value will be affected by the delay however we observe it. That being so, fromPoll won't work for an application-driving clock, which requires tracking continuous change with some accuracy.
Implicit in all of the above is that reactive-banana has no built-in notion of time. There are only the "logical" time lines within each stream, which can be interwoven by merging streams. So if we want a current time behaviour our best bet is building one from an independent stream. Here is a demo of that approach, which will produce fresh and timely results as far as the precision of threadDelay allows:
{-# LANGUAGE RankNTypes #-}
module Main where
import Control.Concurrent
import Control.Monad
import Data.Time
import Reactive.Banana
import Reactive.Banana.Frameworks
main = do
let netDesc :: forall t. Frameworks t => Moment t ()
netDesc = do
(eTime, fireTime) <- newEvent
liftIO . forkIO . forever $
threadDelay (50 * 1000) >> getCurrentTime >>= fireTime
bTime <- flip stepper eTime <$> liftIO getCurrentTime
(eTick, fireTick) <- newEvent
liftIO . forkIO . forever $
threadDelay (5000 * 1000) >> fireTick ()
reactimate $ print <$> bTime <# eTick
network <- compile netDesc
actuate network >> threadDelay (52000 * 1000) >> pause network
bTime is updated through eTime each 0.05s; it is observed through eTick, a stream independent from eTime with occurrences every 5s. You can then use eTick and streams derived from it to observe and update your entities. Alternatively, you can combine bTime and the entity behaviours in applicative style to get, e.g. behaviours for the latest pings, to be observed with eTick.
Having a canonical time behaviour looks like a sound approach in your case; it is conceptually clear and readily generalisable for multiple ticks. In any case, other approaches that you can play with include getting rid of bTime and using eTick as a low-resolution current time stream (though that seems to make the threadDelay innacurcies build up faster), and getting rid of eTick by using changes to get a stream of freshly updated values from the behaviour (through that comes with its own quirks and annoyances, as the documentation hints at).

Related

Why does changing my FRP implementation to be more reactive lag?

I got a version of snake working with the threepenny-gui library, but I didn't like the fact that I was explicitly calling newEvent and addStateUpdate manually instead of defining the behavior completely based on events, e.g. this:
(updates, addUpdate) <- liftIO newEvent
managerB <- accumB initialManager updates
on UI.tick timer $ \_ -> addUpdate $ \manager -> manager'
compared to:
managerB <- accumB initialManager $
UI.tick timer $> \manager -> manager'
IIUC the second is more idiomatic FRP, as it defines a behavior with the actual event instead of creating a proxy event to proxy updates through. But when I make this change, it causes one of two problems:
If I define managerB first (using RecursiveDo to access timer, which is defined below), nothing's rendered at all
If I move managerB to the end (using RecursiveDo to access managerB from the DOM elements), the initial movement when hitting an arrow key for the first time lags, and the frames render in a jerky fashion.
Am I doing something wrong? What's the idiomatic way I should structure these events/behaviors?
Code diff here: https://github.com/brandonchinn178/snake/compare/inline-event-handlers
A not particularly pretty workaround for the jerkiness, which I tested on the alternate branch in your repository, is, so to say, using both approaches at once: re-firing the tick event and using that instead of UI.tick timer to define managerB:
(timeE, fireTime) <- liftIO newEvent
on UI.tick timer $ \_ -> liftIO (fireTime ())
let managerUpdateE =
fmap concatenate . unions $
[ timeE $> getNextManagerState
-- Instead of: UI.tick timer $> getNextManagerState
-- etc.
The issue appears to be that plugging UI.tick timer directly into the event network somehow gets in the way of Threepenny sending the JavaScript calls needed to update the UI in a timely way. The indirection in using on with fireTime (which, in particular, should mean timeE happens notionally after UI.tick timer) seems to skirt around the problem. A less intrusive workaround would be, instead of introducing timeE, explicitly calling flushCallBuffer in a handler for UI.tick timer; in my tests, however, that reduced the jerkiness a lot but didn't eliminate it completely. (See also threepenny-gui issue #191 for possibly relevant background information.)
As for the delay on the first keystroke, it appears that can be eliminated by moving your invocation of UI.start timer to the very end of gui, after managerB and the rest of your event network is set up.
(On an additional note, it is probably a good idea to follow the recommendation of the Graphics.UI.Threepenny.Timer docs and set -threaded in the ghc-options for compiling your executable, even if that doesn't seem to have an effect on the problem you describe here.)

Reactive Banana: Bindings

I am working on a small terminal-based UI and I want to use Reactive Banana for describing interactions. The only external event I am interested in, is whether the user has pressed a key.
From what I gathered from the Frameworks documentation, I can either use polling to get the state of the terminal input buffer or pass an "event handler" to Reactive Banana. I'd rather prefer the latter, but I find the event handling section confusing. How exactly would I describe an event-driven version of getChar? In the end, I'd like to operate on an "Event Key" stream.
I have looked at the SDL and wx bindings, but I don't find them of much help, since they are littered with library related idiosyncracies, and I'd much appreciate a more concise explanation how event handlers, event loops and Reactive Banana mix together.
As it turns out, dealing with external events is remarkably flexible and simple with Reactive Banana. All that is needed is to create an event handler with "newAddHandler" which consists of two pieces, an "AddHandler" from which events can be created using the reactimate function, and a Handler which has to be invoked by the glue code (binding) that bridges Reactive Banana to the framework (in my case, I just feed the result of getChar to the handler).
Here is an example code that echos keystrokes:
echo = do
(keyEventHandler, fire) <- newAddHandler
-- Network Specification (echo keyboard input)
let networkDescription =
fromAddHandler keyEventHandler >>= -- Create event stream from handler
reactimate . fmap print -- Map print over event stream
compile networkDescription >>= actuate
-- Event Loop
hSetBuffering stdin NoBuffering
forever $ do
ready <- hReady stdin
if ready
then getChar >>= fire -- Create keyboad event
else return ()
The nice thing about reactive banana is that the callback function "fire" can be invoked from any context. Thus, the event loop could as well run in a thread or be invoked from a C library. More about this can be found by Heinrich's answer to How to implement a game loop in reactive-banana?.
However, catching arbitrary keyboard input events without polling is not as easy as I thought, POSIX won't allow it (if I am not mistaken) and even if it did the code would not be portable.
Also note that on Windows machines, you have to hit enter, I still have to find a way around that problem. More on this issue is found at the Haskell bugtracker

STM-friendly list as a change log

I need an advice on the data structure to use as an atomic change log.
I'm trying to implement the following algorithm. There is a flow of incoming
changes updating an in-memory map. In Haskell-like pseudocode it is
update :: DataSet -> SomeListOf Change -> Change -> STM (DataSet, SomeListOf Change)
update dataSet existingChanges newChange = do
...
return (dataSet, existingChanges ++ [newChange])
where DataSet is a map (currently it is the Map from the stm-containers package, https://hackage.haskell.org/package/stm-containers-0.2.10/docs/STMContainers-Map.html). The whole "update" is called from arbitrary number of threads. Some of the Change's can be rejected due to domain semantics, I use throwSTM for that to throw away the effect of the transaction. In case of successful commit the "newChange" is added to the list.
There exists separate thread which calls the following function:
flush :: STM (DataSet, SomeListOf Change) -> IO ()
this function is supposed to take the current snapshot of DataSet together with the list of changes (it has to a consistent pair) and flush it to the filesystem, i.e.
flush data = do
(dataSet, changes) <- atomically $ readTVar data_
-- write them both to FS
-- ...
atomically $ writeTVar data_ (dataSet, [])
I need an advice about the data structure to use for "SomeListOf Change". I don't want to use [Change] because it is "too ordered" and I'm afraid there will be too many conflicts, which will force the whole transaction to retry. Please correct me, if I'm wrong here.
I cannot use the Set (https://hackage.haskell.org/package/stm-containers-0.2.10/docs/STMContainers-Set.html) because I still need to preserve some order, e.g. the order of transaction commits. I could use TChan for it and it looks like a good match (exactly the order of transaction commits), but I don't know how to implement the "flush" function so that it would give the consistent view of the whole change log together with the DataSet.
The current implementation of that is here https://github.com/lolepezy/rpki-pub-server/blob/add-storage/src/RRDP/Repo.hs, in the functions applyActionsToState and rrdpSyncThread, respectively. It uses TChan and seems to do it in a wrong way.
Thank you in advance.
Update: A reasonable answer seems to be like that
type SomeListOf c = TChan [c]
update :: DataSet -> TChan [Change] -> Change -> STM DataSet
update dataSet existingChanges newChange = do
...
writeTChan changeChan $ reverse (newChange : existingChanges)
return dataSet
flush data_ = do
(dataSet, changes) <- atomically $ (,) <$> readTVar data_ <*> readTChan changeChan
-- write them both to FS
-- ...
But I'm still not sure whether it's a neat solution to pass the whole list as an element of the channel.
I'd probably just go with the list and see how far it takes performance-wise. Given that, you should consider that both, appending to the end of a list and reversing it are O(n) operations, so you should try to avoid this. Maybe you can just prepend the incoming changes like this:
update dataSet existingChanges newChange = do
-- ...
return (dataSet, newChange : existingChanges)
Also, your example for flush has the problem that reading and updating the state is not atomic at all. You must accomplish this using a single atomically call like so:
flush data = do
(dataSet, changes) <- atomically $ do
result <- readTVar data_
writeTVar data_ (dataSet, [])
return result
-- write them both to FS
-- ...
You could then just write them out in reverse order (because now changes contains the elements from newest to oldest) or reverse here once if it's important to write them out oldest to newest. If that's important I'd probably go with some data structure which allows O(1) element access like a good old vector.
When using a fixed-size vector you would obviously have to deal with the problem that it can become "full" which would mean your writers would have to wait for flush to do it's job before adding fresh changes. That's why I'd personally go for the simple list first and see if it's sufficient or where it needs to be improved.
PS: A dequeue might be a good fit for your problem as well, but going fixed size forces you to deal with the problem that your writers can potentially produce more changes than your reader can flush out. The dequeue can grow infinitely, but you your RAM probably isn't. And the vector has pretty low overhead.
I made some (very simplistic) investigation
https://github.com/lolepezy/rpki-pub-server/tree/add-storage/test/changeLog
imitating exactly the type of load I supposedly going to have. I used the same STMContainers.Map for the data set and usual list for the change log. To track the number of transaction retries, I used Debug.Trace.trace, meaning, the number of lines printed by trace. And the number of unique lines printed by trace gives me the number of committed transactions.
The result is here (https://github.com/lolepezy/rpki-pub-server/blob/add-storage/test/changeLog/numbers.txt). The first column is the number of threads, the second is the number of change sets generated in total. The third column is the number of trace calls for the case without change log and the last one is the number of trace calls with the change log.
Apparently most of the time change log adds some extra retries, but it's pretty much insignificant. So, I guess, it's fair to say that any data structure would be good enough, because most of the work is related to updating the map and most of the retries are happening because of it.

State-dependent event processing with state updates

I want to use FRP (i.e., reactive banana 0.6.0.0) for my project (a GDB/MI front-end). But I have troubles declaring the event network.
There are commands from the GUI and there are stop events from GDB. Both need to be handled and handling them depends on the state of the system.
My current approach looks like this (I think this is the minimum required complexity to show the problem):
data Command = CommandA | CommandB
data Stopped = ReasonA | ReasonB
data State = State {stateExec :: Exec, stateFoo :: Int}
data StateExec = Running | Stopped
create_network :: NetworkDescription t (Command -> IO ())
create_network = do
(eCommand, fCommand) <- newEvent
(eStopped, fStopped) <- newEvent
(eStateUpdate, fStateUpdate) <- newEvent
gdb <- liftIO $ gdb_init fStopped
let
eState = accumE initialState eStateUpdate
bState = stepper initialState eState
reactimate $ (handleCommand gdb fStateUpdate <$> bState) <#> eCommand
reactimate $ (handleStopped gdb fStateUpdate <$> bState) <#> eStopped
return fCommand
handleCommand and handelStopped react on commands and stop events depending on the current state. Possible reactions are calling (synchronous) GDB I/O functions and firing state update events. For example:
handleCommand :: GDB -> ((State -> State) -> IO ()) -> State -> Command -> IO ()
handleCommand gdb fStateUpdate state CommandA = case stateExec state of
Running -> do
gdb_interrupt gdb
fStateUpdate f
where f state' = state' {stateFoo = 23}
The problem is, when f gets evaluated by accumE, state' sometimes is different from state.
I am not 100% sure why this can happen as I don't fully understand the semantics of time and simultaneity and the order of "reactimation" in reactive banana. But I guess that state update functions fired by handleStopped might get evaluated before f thus changing the state.
Anyway, this event network leads to inconsistent state because the assumptions of f on the "current" state are sometimes wrong.
I have been trying to solve this problem for over a week now and I just cannot figure it out. Any help is much appreciated.
It looks like you want to make a eStateUpdate event occur whenever eStop or eCommand occurs?
If so, you can simply express it as the union of the two events:
let
eStateUpdate = union (handleCommand' <$> eCommand)
(handleStopped' <$> eStopped)
handleCommand' :: Command -> (State -> State)
handleStopped' :: Stopped -> (State -> State)
eState = accumE initialState eStateUpdate
etc.
Remember: events behave like ordinary values which you can combine to make new ones, you're not writing a chain of callback functions.
The newEvent function should only be used if you want to import an event from the outside world. That's the case for eCommand and eStopped, as they are triggered by the external GDB, but the eStateUpdate event seems to be internal to the network.
Concerning behavior of your current code, reactive-banana always does the following things when receiving an external event:
Calculate/update all event occurrences and behavior values.
Run the reactimates in order.
But it may well happen happen that step 2 triggers the network again (for instance via the fStateUpdate function), in which case the network calculates new values and calls the reactimates again, as part of this function call. After this, flow control returns to the first sequence of reactimates that is still being run, and a second call to fStateUpdate will have strange effects: the behaviors inside the network have been updated already, but the argument to this call is still an old value. Something like this:
reactimate1
reactimate2
fStateUpdate -- behaviors inside network get new values
reactimate1'
reactimate2'
reactimate3 -- may contain old values from first run!
Apparently, this is tricky to explain and tricky to reason about, but fortunately unnecessary if you stick to the guidelines above.
In a sense, the latter part embodies the trickiness of writing event handlers in the traditional style, whereas the former part embodies the (relative) simplicity of programming with events in FRP-style.
The golden rule is:
Do not call another event handler while handling an event.
You don't have to follow this rule, and it can be useful at times; but things will become complicated if you do that.
As far as I can see, FRP seems not to be the right abstraction for my problem.
So I switched to actors with messages of type State -> IO State.
This gives me the required serialization of events and the possibility to do IO when updating the state. What I loose is the nice description of the event network. But it's not too bad with actors either.

Is the random number generator in Haskell thread-safe?

Is the same "global random number generator" shared across all threads, or does each thread get its own?
If one is shared, how can I ensure thread-safety? The approach using getStdGen and setStdGen described in the "Monads" chapter of Real World Haskell doesn't look safe.
If each thread has an independent generator, will the generators for two threads started in rapid succession have different seeds? (They won't, for example, if the seed is a time in seconds, but milliseconds might be OK. I don't see how to get a time with millisecond resolution from Data.Time.)
There is a function named newStdGen, which gives one a new std. gen every time it's called. Its implementation uses atomicModifyIORef and thus is thread-safe.
newStdGen is better than get/setStdGen not only in terms of thread-safety, but it also guards you from potential single-threaded bugs like this: let rnd = (fst . randomR (1,5)) <$> getStdGen in (==) <$> rnd <*> rnd.
In addition, if you think about the semantics of newStdGen vs getStdGen/setStdGen, the first ones can be very simple: you just get a new std. gen in a random state, chosen non-deterministically. On the other hand, with the get/set pair you can't abstract away the global program state, which is bad for multiple reasons.
I would suggest you to use getStdGen only once (in the main thread) and then use the split function to generate new generators. I would do it like this:
Make an MVar that contains the generator. Whenever a thread needs a new generator, it takes the current value out of the MVar, calls split and puts the new generator back. Due to the functionality of an MVar, this should be threadsafe.
By itself, getStdGen and setStdGen are not thread safe in a certain sense. Suppose the two threads both perform this action:
do ...
g <- getStdGen
(v, g') <- someRandOperation g
setStdGen g'
It is possible for the threads to both run the g <- getStdGen line before the other thread reaches setStdGen, therefore they both could get the exact same generator. (Am I wrong?)
If they both grab the same version of the generator, and use it in the same function, they will get the same "random" result. So you do need to be a little more careful when dealing with random number generation and multithreading. There are many solutions; one that comes to mind is to have a single dedicated random number generator thread that produces a stream of random numbers which other threads could consume in a thread-safe way. Putting the generator in an MVar, as FUZxxl suggests, is probably the simplest and most straightforward solution.
Of course I would encourage you to inspect your code and make sure it is necessary to generate random numbers in more than one thread.
You can use split as in FUZxxl's answer. However, instead of using an MVar, whenever you call forkIO, just have your IO action for the forked thread close over one of the resulting generators, and leave the other one with the original thread. This way each thread has its own generator.
As Dan Burton said, do inspect your code and see if you really need RNG in multiple threads.

Resources