Reputation: 16079
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!
Upvotes: 3
Views: 1462
Reputation: 16079
I think I'm sort of fleshing out pigworker's comment on the question.
ensure :: GameState Bool -> GameState () -> GameState ()
ensure p k = do
t <- p
when t k
addPoints num = do
ensure (evenResult num) $ do
...
Which is close enough. I'm sure ehird's answer is more correct, but it also seems a lot more complicated than I wanted. So much to learn still :)
Upvotes: 0
Reputation: 40797
Import Control.Monad.Trans.Maybe
and use MaybeT
on top of StateT
. Then, you can use mzero
to abort the computation or, like Kevin Ballard says, guard condition
to stop if condition
is False
; all you have to do is enclose each block in runMaybeT
. (Note that you'll either have to lift
every option you have defined on your StateT
monad, or change their types to work with any monad with the state you require, like operation :: (MonadState m Game) => ...
.)
Note that you probably have the transformers
package that Control.Monad.Trans.Maybe
is contained in, even if you're not using it directly; the mtl
package, which contains the standard monad modules like Control.Monad.State
, depends on it.
Upvotes: 7