I am implementing a game engine. Most of my code currently resides in a StateT Game IO ()
monad. I use IO to get user input, and in fact all IO channels through one function,
getChoice :: Show a => [ a ] -> IO a
which prompts the user with all presented options, reads in a response, and returns it. For a particular flow of user responses (and initial state), the game proceeds deterministically, and I'd like to factor out these user responses to help with testing.
When I try to convert this to use Pipes, what feels most similar is to change all my code which is currently in StateT Game IO ()
, and make it run in Proxy p, Monad m => Client p [String] String m ()
. This way I can still 'request' choices from the user, which allows me to write the engine code in a blocking style, assuming that user choices will be provided as I need them.
However, this seems wrong - surely the user should be the Client, and the game engine the Server? What principles can I use to make this distinction correctly?