I have a type that represents game state for my application, for this question pretend it is something simple like:
Game { points :: Int }
I define my game logic with the State monad.
type GameState a = StateT Game a
addPoints :: Int -> GameState ()
addPoints num = do
Game p <- get
put $ Game (p+num)
I want to be able to simply discard some inputs
evenResult num = do
Game p <- get
return $ even (p + num)
addPoints num = do
isEven <- evenResult num
if isEven then return () else do
Game n <- get
put $ Game (n+num)
I want a syntax that looks something like this
addPoints num = do
guard evenResult
...
-- or this
addPoints num = do
guardIsEvenResult
...
If it hits the guard, I want it to leave the state alone, and do nothing else in the block.
How can I do it? It seems close to possible with MonadPlus, but I’m not sure I could use mzero to say “return what you already have in your state”. Thanks!
Import
Control.Monad.Trans.Maybeand useMaybeTon top ofStateT. Then, you can usemzeroto abort the computation or, like Kevin Ballard says,guard conditionto stop ifconditionisFalse; all you have to do is enclose each block inrunMaybeT. (Note that you’ll either have toliftevery option you have defined on yourStateTmonad, or change their types to work with any monad with the state you require, likeoperation :: (MonadState m Game) => ....)Note that you probably have the
transformerspackage thatControl.Monad.Trans.Maybeis contained in, even if you’re not using it directly; themtlpackage, which contains the standard monad modules likeControl.Monad.State, depends on it.