Say that I'm implementing a TicTacToe game server. In order to better test it I define a class for the effect of getting a move from a player:
class (Monad m, MonadState TTTState m) => TTTMonad m where
getMove :: m Move
In "production" the getMove will be an IO action waiting for input from the user, but when testing this I want to provide a list of pre canned Moves to replay a particular game.
So my initial approach was to create a tuple with the moves to be replayed and the TTTState itself:
newtype ReplayMonad a = ReplayMonad { unReplay :: State ([Move], TTTState) a }
but then I cannot have MonadState [Move] and MonadState TTTState for the same monad instance because of the functional dependency. I want this double dependency because I wanted to do:
instance TTTMonad ReplayMonad where
-- Consume the first move in the list and provide it as a result of the context
getMove = do
m:ms <- gets fst
modify (\(_, gs) -> (ms, gs)) -- Have a new state with the remaining moves
return m
All my code is only parameterized by MonadState TTTState and I just wanted to introduce the extra piece of state because I need to retrive Moves from within the context of the monad.
What am I doing wrong? What is the usual pattern to deal with this kind of extensions to a simpler monad?
You don't need two
MonadStateinstances. You only needMonadState TTTStatesince it is a superclass ofTTTMonad, but instead ofMonadState ([Move], TTTState)you can either have specialized variants ofgetandputforReplayMonador use the
ReplayMonadconstructor, since the underlying monad exactly gives you access to the whole state.