Should I consider the state as the Behaviors that I define in the code?
For most scenarios you will indeed want to use Behavior
s for state. In a GUI application you will often want to update your state in response to interface events. In addition, and crucially, the state must remain existing between occurrences of the events, and State
doesn't allow that. More specifically, the standard way to react to an event occurrence doing something other than updating a Behavior
is through the reactimate
function:
reactimate :: Frameworks t => Event t (IO ()) -> Moment t ()
The action to be performed is of type IO ()
. While it is possible to use runStateT
to run a StateT s IO
computation using reactimate
, the computation will be self-contained, and you won't have the state it used available to be passed elsewhere. This problem does not arise when using Event
s to update Behavior
s through the reactive-banana FRP interface: the Behavior
s remain there until you need to use them again.
If the state depends on external "events" too, not only related to the GUI would be better considering IORef?
Not necessarily. In many cases you can use the tools in Reactive.Banana.Frameworks
such as fromAddHandler
and newEvent
to create Event
s that are fired when external I/O actions happen. That way you can integrate such actions to your event network. One typical example would be a timer: reactive-banana has no built-in notion of time, but you can introduce a tick event that is fired through an I/O action that happens at regular intervals.
That said, in some cases you might still want to use...
... IORef
s (or other sorts of mutable variables, such as MVar
s), if you have to use a library with an interface that, for whatever reason, restricts your ability to freely react to events using Behavior
s and reactimate
. A while ago there was a very nice question about such a scenario involving hArduino
. The two answers there show different, yet similar in spirit, ways to have an useful event network in unfavourable circumstances.
... StateT
if you have some stateful algorithm that is self-contained and whose results won't be used elsewhere in your event network, so that you can run it with runStateT
and stick it in a reactimate
call. Silly example: an IO ()
action in reactimate
along these lines:
displayMessageBox . show =<< evalStateT someStateComputation initialState