Thanks a lot Jeremy.<br>That was also what I finally understood.<br>I cannot coerce MACID into using my monads.<br><br>Instead, in each of my methods, I have to extract the update and query parts, put them into different functions, and then<br>
register these functions into the MACID system.<br>Well, this is a bit of refactoring ;)<br><br>Indeed, the game is multithreaded / multiplayer.<br>But only one thread accesses the state of the game (the multiplexing is done before).<br>
Perhaps this should be made obvious/enforced by the types. But I&#39;m not yet completely at ease with the STM right now.<br><br>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.<br>
<br>Cheers,<br>Corentin<br><br><br><br><div class="gmail_quote">On Mon, Nov 8, 2010 at 3:29 AM, Jeremy Shaw <span dir="ltr">&lt;<a href="mailto:jeremy@n-heptane.com">jeremy@n-heptane.com</a>&gt;</span> wrote:<br><blockquote class="gmail_quote" style="margin: 0pt 0pt 0pt 0.8ex; border-left: 1px solid rgb(204, 204, 204); padding-left: 1ex;">
<div style="word-wrap: break-word;">Hello,<div><br></div><div>Retrofitting MACID will not be trivial because it makes different assumptions that permeate your code. </div><div><br></div><div>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 ?</div>
<div><br></div><div>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. </div>
<div><br></div><div>MACID will be a lot closer to a traditional database where you perform a distinct &#39;query&#39; operation which updates or reads the state. </div><div><br></div><div>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.</div>
<div><br></div><div>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.</div><div><br></div><div>One question is, what exactly are you trying to achieve.</div>
<div><br></div><div>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.</div>
<div><br></div><div>MACID builds on that to add the ability to log every &#39;update&#39; 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 &#39;event&#39;. And you have to be able to replay those events later and arrive at the same final state you did the first time.</div>
<div><br></div><div>So, in MACID, your events are *written* in the Update and Query monads.</div><div><br></div><div>To specific where an &#39;event&#39; 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.</div>
<div><br></div><div>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.</div><div>
<br></div><div>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.</div>
<div><br></div><div>If you merely want periodic checkpoints, you can use happstack-data and just write the state out periodically.</div><div><br></div><div>hope this helps!</div><div><br></div><div>If I have still not answered your question, or you have others, feel free to ask!</div>
<div><br></div><font color="#888888"><div>- jeremy</div></font><div><div></div><div class="h5"><div><br></div><div><br><div><div>On Nov 7, 2010, at 10:02 AM, Corentin Dupont wrote:</div><br><blockquote type="cite">Hello Jeremy,<br>
thanks for your mail.<br><br>I am in despair on this problem since days, I would really help your help.<br>I can&#39;t figure out how I can add MACID into my program.<br>Here&#39;s the problem:<br>I already have monads in my program like that:<br>
 <br>&gt; type Comm = StateT Communication IO<br> &gt;<br> &gt; type GameState a = StateT Game Comm a<br><br>Many functions make use of GameState.<br>The only type that need to be serialized is Game.<br>The type Communication contains TChans used for players communication.<br>
The IO in Comm is necessary to make some print outs and to use an interpretor when needed (Hint).<br> <br>How can this match with the Update type in Happstack?<br><br>Thanks a lot for your help.<br>Corentin<br><br><br><div class="gmail_quote">
On Fri, Nov 5, 2010 at 3:50 AM, Jeremy Shaw <span dir="ltr">&lt;<a href="mailto:jeremy@n-heptane.com" target="_blank">jeremy@n-heptane.com</a>&gt;</span> wrote:<br> <blockquote class="gmail_quote" style="margin: 0pt 0pt 0pt 0.8ex; border-left: 1px solid rgb(204, 204, 204); padding-left: 1ex;">
Hello,<br> <br> I added a brief section to the happstack crash course on using MACID:<br> <br> <a href="http://www.happstack.com/docs/crashcourse/HappstackState.html" target="_blank">http://www.happstack.com/docs/crashcourse/HappstackState.html</a><br>
 <br> That should hopefully get you started.<br> <br> The example uses happstack state with happstack server. But there is<br> really no connection between the two.<br> <br> Hope this helps! If you have additional questions, feel free to ask!<br>
 <br> - j<br> <div><div></div><div><br> <br> On Thu, Nov 4, 2010 at 12:48 PM, Dupont Corentin<br> &lt;<a href="mailto:corentin.dupont@gmail.com" target="_blank">corentin.dupont@gmail.com</a>&gt; wrote:<br> &gt; Hello,<br>
 &gt; I&#39;m wondering how can I use Happstack&#39;s MACID in my application without<br> &gt; breaking everything.<br> &gt;<br> &gt; I have a monad like that:<br> &gt;<br> &gt; type Comm = StateT Communication IO<br> &gt;<br>
 &gt; type GameState a = StateT Game Comm a<br> &gt;<br> &gt; and many functions like:<br> &gt; foo :: GameState ()<br> &gt; foo = do<br> &gt;    lift $ putComm &lt;some message to player&#39;s channel&gt;<br> &gt;    modify &lt;someAction&gt;<br>
 &gt;<br> &gt; The state of the game is stored in Game.<br> &gt; Comm is used as an abstraction to communicate over several channels with<br> &gt; players.<br> &gt;<br> &gt; Whereas MACID asks to use:<br> &gt;<br> &gt; type Update state = Ev (StateT state STM)<br>
 &gt;<br> &gt; How can I use this without modifying everything??<br> &gt; I understand that MACID must record the &lt;someAction&gt; from above but the<br> &gt; message should not.<br> &gt;<br> &gt; Thanks for help!<br> &gt;<br>
 &gt; Corentin<br> &gt;<br> &gt;<br> &gt;<br> &gt;<br> </div></div>&gt; _______________________________________________<br> &gt; Haskell-Cafe mailing list<br> &gt; <a href="mailto:Haskell-Cafe@haskell.org" target="_blank">Haskell-Cafe@haskell.org</a><br>
 &gt; <a href="http://www.haskell.org/mailman/listinfo/haskell-cafe" target="_blank">http://www.haskell.org/mailman/listinfo/haskell-cafe</a><br> &gt;<br> &gt;<br> </blockquote></div><br></blockquote></div><br></div></div>
</div></div></blockquote></div><br>