I have an interface (WX) which is based on Reactive Banana.
Now I have different questions about how to really manage the status:
Should I consider the state as the Behaviors that I define in the code?
If the state depends on external "events" too, not only related to the GUI would be better considering IORef?
Or Can I use State Monad? All the examples I saw till now define the network in IO environment. Have any sense stack State Monad and how? With Moment?
Should I consider the state as the Behaviors that I define in the code?
For most scenarios you will indeed want to use Behaviors 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 Events to update Behaviors through the reactive-banana FRP interface: the Behaviors 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 Events 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...
... IORefs (or other sorts of mutable variables, such as MVars), if you have to use a library with an interface that, for whatever reason, restricts your ability to freely react to events using Behaviors 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
Related
I am writing a game in Haskell in which the player and the AI are taking some actions in turns. Until now, the AIs worked by generating actions using all the information about the game, i.e they were functions of the form GameHistory -> GameState -> Action.
This way these functions generate some information they need from the history each time they are called. It would be a lot easier to write AIs if they could have some kind of "internal state" which persists between their turns (i.e. calls to the corresponding function). How could one implement something like that? (By the way, I should also take into account that internal states of different kinds of AIs could have different types.)
What you're looking for might be something like:
newtype AI = AI { runAI :: GameState -> (AI, Action) }
i.e. you'll return your actor's new state along with the action. You might make use of the State monad here. You might also be interested in reading about automata. If you need to serialize your AI (to store it in a database, say) then you might need to do something different.
I've just been investigating FRP in Haskell (mainly reactive-banana (testimonials!)), and I'm wondering is it common for them, and in case of reactive-banana what's the reason to operate in IO monad instead of being constrained to MonadIO, or rven better, any Monad (so that I could provide own stack)?
It seems to me that's because of focus on GUI programming, where you integrate it with some existing libraries that operate in IO? Would it be feasible to change it so that I could integrate it with custom monad stack?
If you are asking why
reactimate :: Frameworks t => Event t (IO ()) -> Moment t ()
expects an event with values of type IO () instead of allowing for a custom monad M () with instance MonadIO M, then the answer is this:
In practice, custom monad stacks only add state/reader/writer effects to the base IO monad. However, in theory, it is entirely possible to add fancy control mechanism like coroutines or non-determinism. I don't know how to integrate the internal state arising from combinators accumE with these more general effects, and I have no idea what it means for an event to happen in a non-deterministic context. That's why reactimate is restricted to IO.
If you have a custom monad stack that is of the state/reader/writer family, then it is usually possible to map it to a pure IO computation and use this with reactimate. If you find that this doesn't work out (I do think that there might be a problem), I would need a more detailed description of the concrete situation to be able to help.
First of all a disclaimer, I might have misunderstood completely the way threepenny-gui works due to my not so advanced knowledge of Haskell, so take my assertions with a grain of salt. :-)
It seems to me that some combinators are not pure e.g.
stepper :: MonadIO m => a -> Event a -> m (Behavior a)
Is stepper necessarily operating on some type of IO monad (and it's therefore not pure), or I'm I misunderstanding something here ? Second question, if those combinators are indeed unpure, why is that ? To me this makes the code for building the event graph much less nice then reactive-banana since one has to use an IO monad instead of being just pure plain functions. The code seems to just become more complicated then in reactive-banana.
Even more scary, valueChange appears to be pure from the type
valueChange :: Element -> Event String
but it's actually using unsafeMapIO inside, so is it actually doing hidden IO ? Again, I might be misunderstanding something, but isn't this the most supreme sin in Haskell ? It was also confusing, I couldn't tell from type how the call-back registration was happening... this never happened to me before in Haskell... Was this done to spare users having to deal with the Frameworks monad ?
I'm not a threepenny-gui user, but I can give you a bit of info on your questions from my reading of the code.
Firstly regarding stepper: It seems that internally threpenny-gui uses IORefs to keep track of accumulating parameters. That's why stepper requires MonadIO. However, I do not think this requires IO to build your event graph, it just means it has to run in IO. This shouldn't cause any awkwardness for you as an API user. If you think it does please post a more specific question.
Secondly regarding valueChange being implemented in terms of an unsafe function: Yes, this is very common to see in Haskell libraries. Haskell library authors often use unsafe functions when they know the way that they are used is actually safe for all possible execution paths, but it is not possible to prove this to the type system. In other words, library authors use unsafe operations in a safe way so that you don't have to!
This answer is complementary to Tom Ellis'. It covers how I would justify the monadic FRP combinators from the perspective of a Threepenny user.
With Threepenny, odds are that a large part of your event graph will be built from Elements, which live in UI (a thin wrapper for IO) because they are tied to a DOM in a browser. That being so, it makes sense to remove the indirection involved in externally plugging something like reactive-banana (as the old reactive-banana-threepenny package used to do). In the case of reactive-banana-threepenny the indirection was not limited to having to use the Frameworks monad, but it also involved converting between the different event types of reactive-banana and Threepenny (it is also worth considering that FRP in Threepenny is optional; you can also use events in a traditional, imperative fashion).
Overall, it is a trade-off: to eliminate some indirection and make the API more immediately accessible, some cleanliness in defining the event graphs is sacrificed. In my experience, however, the trade-off is worth it.
On a closing note, this discussion I had with Heinrich around the time of the switch away from reactive-banana-threepenny may shed some more light on the matter.
I'm looking to write a generic module that allows Haskell programs to interact with Cassandra. The module will need to maintain its own state. For example, it will have a connection pool and a list of callbacks to be invoked when a new record is saved. How should I structure the code so that this module can maintain its state? Here are some of the approaches I've been considering. Am I on the right track? (I'm new to Haskell and still learning the best ways to think functionally.)
Option 1:
The module runs in a (StateT s IO) monad, where s is the global state for the entire program using the Cassandra module. Of course, since the Cassandra module could be used by multiple programs, the details of what's in s should be invisible to the Cassandra module. The module would have to export a type class that allowed it to extract the CassandraState from s and push a new CassandraState back into s. Then, any program using the module would have to make its main state a member of this type class.
Option 2:
The module runs in a (StateT CassandraState IO) monad. Every time someone calls an action in the module, they would have to extract the CassandraState from wherever they have it stashed off, invoke the action with runState, and take the resulting state and stash it off again (wherever).
Option 3:
Don't put the Cassandra module's functions in a StateT monad at all. Instead, have the caller explicitly pass in CassandraState's when needed. The problem with option 2 is that not all of the functions in the module will modify the state. For example, obtaining a connection will modify the state and will require the caller to stash off the resulting state. But, saving a new record needs to read the state (to get the callbacks), but it doesn't need to change the state. Option 2 doesn't give the caller any hint that connect changes the state while create doesn't.
But, if I move away from using the StateT monad and just have functions that take in states as parameters and return either simple values or tuples of simple values and new states, then it's really obvious to the caller when the state needs to be saved off. (Under the covers in my module, I'd take the incoming states and build them into a (StateT CassandraState IO) monad, but the details of this would be hidden from the caller. So, to the caller, the interface is very explicit, but under the covers, it's just Option 2.)
Option 4:
Something else?
This problem must come up quite often when building reusable modules. Is there some sort of standard way to solve it?
(By the way, if someone knows a better way to interact with Cassandra from Haskell than using Thrift, please let me know! Maybe I don't have to write this at all. :-)
Something like the HDBC model would be to have an explicit CassandraConnection data type. It has an MVar inside with some mutable state. Since all your actions are in IO anyway I'd imagine, they can just take the CassandraConnection as an argument to these actions. The user then can pack that connection into a state or reader monad, or thread it explicitly, or do whatever they want.
Internally you can use a monad or not -- that's really your call. However, I favor APIs that when possible don't force users into any particular monad unless truly necessary.
So this is a sort of version of option 3. But the user shouldn't really care whether or not they're changing the connection state -- at that level you can really hide the details from them.
I'd go with Option 2. Users of your module shouldn't use runState directly; instead, you should provide an opaque Cassandra type with an instance of the Monad typeclass and some runCassandra :: Cassandra a -> IO a operation to "escape" Cassandra. The operations exported by your module should all run in the Cassandra monad (e.g. doSomethingInterestingInCassandra :: Int -> Bool -> Cassandra Char), and their definition can access the wrapped CassandraState.
If your users need some additional state for their application, they can always wrap a monad transformer around Cassandra, e.g. StateT MyState Cassandra.
I have a set of Happstack.State MACID methods that I want to test using QuickCheck, but I'm having trouble figuring out the most elegant way to accomplish that. The problems I'm running into are:
The only way to evaluate an Ev monad computation is in the IO monad via query or update.
There's no way to create a purely in-memory MACID store; this is by design. Therefore, running things in the IO monad means there are temporary files to clean up after each test.
There's no way to initialize a new MACID store except with the initialValue for the state; it can't be generated via Arbitrary unless I expose an access method that replaces the state wholesale.
Working around all of the above means writing methods that only use features of MonadReader or MonadState (and running the test inside Reader or State instead of Ev. This means forgoing the use of getRandom or getEventClockTime and the like inside the method definitions.
The only options I can see are:
Run the methods in a throw-away on-disk MACID store, cleaning up after each test and settling for starting from initialValue each time.
Write the methods to have most of the code run in a MonadReader or MonadState (which is more easily testable), and rely on a small amount of non-QuickCheck-able glue around it that calls getRandom or getEventClockTime as necessary.
Is there a better solution that I'm overlooking?
You might checkout out the quickcheck properties that are included with happstack-state:
http://patch-tag.com/r/mae/happstack/snapshot/current/content/pretty/happstack-state/tests/Happstack/State/Tests
If you are just doing testing, and you want a throw-away data store, then you can use the memory saver, which just stores the state, event files, and checkpoints in RAM. If you lose power, then all your state would be lost. That is fine for tests, but not for a real live server. That message you linked to was talk about real live servers, not just testing.
That won't help with the initialValue issue, but it does make option 1 easier since you don't have to do any disk cleanup.
To replace the initialValue, you would need to create your own method that replaces the current state wholesale.
something like:
newState :: YourState -> Update YourState ()
newState st = put st
or something.
jeremy
If you write your functions as polymorphic over MonadState (or MonadReader for queries) it can be a lot easier to set up a test harness with runState/runReader.
The happstack TH code generators are fine with signatures like that, from what I remember.