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!
StateT
is already aMonadPlus
. Have you tried just usingControl.Monad.guard
? – Lily BallardStateT s m
is only aMonadPlus
ifm
is; the instance just liftsmzero
andmplus
one level up. – ehirdwhen
wants aBool
value, rather than a computation that makes aBool
. But Rome wasn't burnt in a day. If yourtest
lives inm Bool
, you could write(test >>=) . flip when $ action
for a tidy kind of perplexity. – pigworker