
Limestraƫl wrote:
Okay, I just understood that 'Prompt' was just a sort of view for 'Program'.
Right.
runMyStackT :: MyStackT (Player m) a -> Player m a
According to what Bertram said, "each strategy can pile its own custom monad stack ON the (Player m) monad".
Yes, and I meant what Heinrich wrote, you wrap some transformer around the common Player m monad.
game :: Monad m => Player m () -> Player m () -> m () As it is written, it requires both players to run in the SAME monad. And if have a network player ( e.g.* Player (StateT Handle IO)* ) and an AI storing former opponent's moves ( e.g. *(Monad m) => Player (StateT [Move] m)* ), then they can't be in the same monad...
The idea is to pick m = IO, and then use type NetPlayer a = StateT Handle (Player IO) a and type AIPlayer a = StateT [Move] (Player IO) a or possibly type AIPlayer a = StateT [Move] (Player Identity) a using the mapPlayerM (or mapMonad as suggested by Heinrich) function. You'd then provide functions like runAIPlayer :: AIPlayer a -> Player IO a runAIPlayer player = {- mapMonad (return . runIdentity) $ -} evalStateT player [] This gives you most of what you want: You can add custom state and the like to each player. You can not hope to exchange the base monad m, because then the 'game' function would have to know how to run both of those base monads simultaneously. A function like mapMonad is the best device you can hope for, I think. regards, Bertram