I have some difficulties to see the use of PromptT, because in the tutorial, this type is never mentioned, and its operations (Return and :>>=) are instead constructors of ProgramT...<br><br>Would you have some concrete examples? Because there I'm a bit lost (since the tutorial doesn't match the operational package as it is, because of the type PromptT)...<br>
<br><div class="gmail_quote">2010/4/14 Heinrich Apfelmus <span dir="ltr"><<a href="mailto:apfelmus@quantentunnel.de">apfelmus@quantentunnel.de</a>></span><br><blockquote class="gmail_quote" style="border-left: 1px solid rgb(204, 204, 204); margin: 0pt 0pt 0pt 0.8ex; padding-left: 1ex;">
Bertram Felgenhauer wrote:<br>
<div class="im">> Yves Parès wrote:<br>
>><br>
>> I answered my own question by reading this monad-prompt example:<br>
>> <a href="http://paste.lisp.org/display/53766" target="_blank">http://paste.lisp.org/display/53766</a><br>
>><br>
>> But one issue remains: those examples show how to make play EITHER a human<br>
>> or an AI. I don't see how to make a human player and an AI play SEQUENTIALLY<br>
>> (to a TicTacToe, for instance).<br>
><br>
> A useful idea is to turn the construction upside-down - rather than<br>
> implementing the game logic using MonadPrompt (or operational),<br>
> implement the players in such a monad.<br>
><br>
> A sketch:<br>
><br>
> {-# LANGUAGE GADTs, EmptyDataDecls #-}<br>
> import Control.Monad.Prompt hiding (Lift)<br>
><br>
> data Game -- game state<br>
> data Move -- move<br>
><br>
> data Request m a where<br>
> Board :: Request m Game<br>
> MakeMove :: Move -> Request m ()<br>
> Lift :: m a -> Request m a<br>
><br>
> type Player m a = Prompt (Request m) a<br>
<br>
</div>Just a small simplification: it is not necessary to implement the Lift<br>
constructor by hand, the operational library implements a generic<br>
monad transformer. The following will do:<br>
<br>
import Control.Monad.Operational<br>
<br>
data Request a where<br>
Board :: Request Game<br>
MakeMove :: Move -> Request ()<br>
<br>
type Player m a = ProgramT Request m a<br>
<div class="im"><br>
game :: Monad m => Player m () -> Player m () -> m ()<br>
</div> game p1 p2 = do<br>
g <- initGame<br>
eval' g p1 p2<br>
where<br>
eval' g p1 p2 = viewT p1 >>= \p1' -> eval g p1' p2<br>
<br>
eval :: Monad m => Game -><br>
-> Prompt Request m ()<br>
-> Player m ()<br>
-> m ()<br>
eval g (Return _) _ = return ()<br>
eval g (Board :>>= p1) p2 = eval' g (p1 g) p2<br>
eval g (MakeMove mv :>>= p1) p2 =<br>
makeMove mv g >>= \g -> eval' g p2 (p1 ())<br>
<br>
This way, you are guaranteed not to break the lifting laws, too.<br>
<div class="im"><br>
> What have we achieved? Both players still can only access functions from<br>
> whatever monad m turns out to be. But now each strategy can pile its own<br>
> custom monad stack on the Player m monad! And of course, the use of<br>
> the m Monad is completely optional.<br>
<br>
</div>Of course, the custom monad stack has to provide a projection back to<br>
the Player m a type<br>
<br>
runMyStackT :: MyStackT (Player m) a -> Player m a<br>
<br>
Fortunately, you can't expect anything better anyway! After all, if the<br>
game function were to accept say LogicT (Player m) as well, this<br>
would mean that the player or AI could interleave the game arbitrarily,<br>
clearly not a good idea.<br>
<div class="im"><br>
> Mapping between various 'm' monads may also be useful:<br>
><br>
> mapPlayerM :: forall m1 m2 a . (forall a . m1 a -> m2 a)<br>
> -> Player m1 a -> Player m2 a<br>
> mapPlayerM m1m2 pl = runPromptC return handle pl where<br>
> handle :: Request m1 x -> (x -> Player m2 a) -> Player m2 a<br>
> handle (Lift a) x = prompt (Lift (m1m2 a)) >>= x<br>
> handle (MakeMove mv) x = prompt (MakeMove mv) >>= x<br>
> handle (Board) x = prompt (Board) >>= x<br>
><br>
> This could be used to lock out the AI player from using IO, say.<br>
<br>
</div>Shouldn't this actually be a member of the MonadTrans class?<br>
<br>
mapMonad :: (Monad m1, Monad m2, MonadTrans t) =><br>
(forall a . m1 a -> m2 a) -> t m1 a -> t m2 a<br>
<br>
?<br>
<br>
Regards,<br>
Heinrich Apfelmus<br>
<font color="#888888"><br>
--<br>
<a href="http://apfelmus.nfshost.com" target="_blank">http://apfelmus.nfshost.com</a><br>
</font><div><div></div><div class="h5"><br>
_______________________________________________<br>
Haskell-Cafe mailing list<br>
<a href="mailto:Haskell-Cafe@haskell.org">Haskell-Cafe@haskell.org</a><br>
<a href="http://www.haskell.org/mailman/listinfo/haskell-cafe" target="_blank">http://www.haskell.org/mailman/listinfo/haskell-cafe</a><br>
</div></div></blockquote></div><br>