Thanks a lot Jeremy. That was also what I finally understood. I cannot coerce MACID into using my monads.
Instead, in each of my methods, I have to extract the update and query parts, put them into different functions, and then register these functions into the MACID system. Well, this is a bit of refactoring ;) Indeed, the game is multithreaded / multiplayer. But only one thread accesses the state of the game (the multiplexing is done before). Perhaps this should be made obvious/enforced by the types. But I'm not yet completely at ease with the STM right now. Perhaps as you suggest this will be a good starting point to first add the checkpoint feature in the soft, then later to migrate it to log every events. Cheers, Corentin On Mon, Nov 8, 2010 at 3:29 AM, Jeremy Shaw <[email protected]> wrote: > Hello, > > Retrofitting MACID will not be trivial because it makes different > assumptions that permeate your code. > > It sounds like your game is possibly multithreaded / multiplayer. But, the > Game is stored the StateT monad. So I assume only one thread updates the > GameState ? Is the Game state per-player or is there only one global game > state ? > > In your current app, any code in the GameState monad can update the state > at any time, and IO can be freely intermixed. There are no really boundaries > separating one state update from another -- it is a continual process with > no clear separate events. > > MACID will be a lot closer to a traditional database where you perform a > distinct 'query' operation which updates or reads the state. > > Each update or query you wanted to perform on the state would become a > separate isolated function which gets registered with the transaction system > (using mkMethod). You would then perform those transactions using the update > and query functions (which run in the IO monad). So you would get rid of the > GameState monad, and just have Comm. > > MACID also deals with the issue of multiple threads trying to update the > state -- but that may not be a problem you care about if you only have one > thread. > > One question is, what exactly are you trying to achieve. > > If you simple want to checkpoint your game state now and then, you could > use just happstack-data. It provides versioned binary serialization and > migration. That would allow you to save the entire state now and then, and > migrate the data when the game state format changed. > > MACID builds on that to add the ability to log every 'update' event that > occurs so that you can replay the events if the server crashes between > checkpoints. (It also allows for distributed state across multiple servers). > But in order to log an event, the app has to first have things when can be > clearly identified as a single 'event'. And you have to be able to replay > those events later and arrive at the same final state you did the first > time. > > So, in MACID, your events are *written* in the Update and Query monads. > > To specific where an 'event' begins and ends, you register some of those > functions with MACID using the mkMethods function. The event starts when a > registered function is called, and ends when that function returns a value. > > In order to be sure that the events can be replayed later and arrive at the > same result, those events can not perform any IO, because the IO might > result in a different answer when replayed. > > So, to answer your question: You will not directly call functions in the > Update monad. And you will not integrated the Update monad into your other > monads. Instead you will register the Update and Query functions via > mkMethods, and call them in the IO monad via query and update. That is > likely to be fairly disruptive to your current design. But it ensures that > every event is saved. > > If you merely want periodic checkpoints, you can use happstack-data and > just write the state out periodically. > > hope this helps! > > If I have still not answered your question, or you have others, feel free > to ask! > > - jeremy > > > On Nov 7, 2010, at 10:02 AM, Corentin Dupont wrote: > > Hello Jeremy, > thanks for your mail. > > I am in despair on this problem since days, I would really help your help. > I can't figure out how I can add MACID into my program. > Here's the problem: > I already have monads in my program like that: > > > type Comm = StateT Communication IO > > > > type GameState a = StateT Game Comm a > > Many functions make use of GameState. > The only type that need to be serialized is Game. > The type Communication contains TChans used for players communication. > The IO in Comm is necessary to make some print outs and to use an > interpretor when needed (Hint). > > How can this match with the Update type in Happstack? > > Thanks a lot for your help. > Corentin > > > On Fri, Nov 5, 2010 at 3:50 AM, Jeremy Shaw <[email protected]> wrote: > >> Hello, >> >> I added a brief section to the happstack crash course on using MACID: >> >> http://www.happstack.com/docs/crashcourse/HappstackState.html >> >> That should hopefully get you started. >> >> The example uses happstack state with happstack server. But there is >> really no connection between the two. >> >> Hope this helps! If you have additional questions, feel free to ask! >> >> - j >> >> >> On Thu, Nov 4, 2010 at 12:48 PM, Dupont Corentin >> <[email protected]> wrote: >> > Hello, >> > I'm wondering how can I use Happstack's MACID in my application without >> > breaking everything. >> > >> > I have a monad like that: >> > >> > type Comm = StateT Communication IO >> > >> > type GameState a = StateT Game Comm a >> > >> > and many functions like: >> > foo :: GameState () >> > foo = do >> > lift $ putComm <some message to player's channel> >> > modify <someAction> >> > >> > The state of the game is stored in Game. >> > Comm is used as an abstraction to communicate over several channels with >> > players. >> > >> > Whereas MACID asks to use: >> > >> > type Update state = Ev (StateT state STM) >> > >> > How can I use this without modifying everything?? >> > I understand that MACID must record the <someAction> from above but the >> > message should not. >> > >> > Thanks for help! >> > >> > Corentin >> > >> > >> > >> > >> > _______________________________________________ >> > Haskell-Cafe mailing list >> > [email protected] >> > http://www.haskell.org/mailman/listinfo/haskell-cafe >> > >> > >> > > >
_______________________________________________ Haskell-Cafe mailing list [email protected] http://www.haskell.org/mailman/listinfo/haskell-cafe
