I have the following function for walking around "edges" of the "graph" of my game world. It alters the state of the world--specifically, the player's location. I need to report a message alerting the player of their change in location as well.
So I could either return a tuple of (message, newWorld), or I could use a State monad. (Right? I'm new to this stuff.)
Here's my attempt at the monad approach:
walk dir = do
world <- get
let attempt = filter (\e -> edgeDirection e == dir) $ edges
edges = (worldEdges world) M.! playerLoc
playerLoc = playerLocation $ worldPlayer world
case attempt of
[] -> return "You can't go that way."
(edge : _) -> do
put world'
return message
where world' = world { worldPlayer = player' }
player' = (worldPlayer world) { playerLocation = loc }
loc = edgeLocation edge
message = "You go " ++ (downcase $ show dir)
The thing is, now the function that calls walk
has a State monad to deal with. Do I runState
it right there, or do I have that function use State monads too, like this:
parseWalk dir =
let direction = case dir of
('e' : _) -> Just East
('n' : _) -> Just North
('s' : _) -> Just South
('w' : _) -> Just West
('u' : _) -> Just Up
('d' : _) -> Just Down
_ -> Nothing
in case direction of
Just d -> walk d
Nothing -> return "You can't go that way"
Then what about parseWalk
's caller, and so forth? Should I try to keep this State monad passed around as long as possible? Should I be seeing a lot of MonadState ...
in my type signatures?