[Haskell-cafe] How can I use MACID in my existing application?

Corentin Dupont corentin.dupont at gmail.com
Mon Nov 8 05:51:03 EST 2010

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
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


On Mon, Nov 8, 2010 at 3:29 AM, Jeremy Shaw <jeremy at n-heptane.com> 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 <jeremy at n-heptane.com> 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
>> <corentin.dupont at gmail.com> 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
>> > Haskell-Cafe at haskell.org
>> > http://www.haskell.org/mailman/listinfo/haskell-cafe
>> >
>> >
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://www.haskell.org/pipermail/haskell-cafe/attachments/20101108/b5d46537/attachment.html

More information about the Haskell-Cafe mailing list