我有一个代表我的应用程序游戏状态的类型,因为这个问题假装它很简单:
Game { points :: Int }
我使用State monad定义我的游戏逻辑。
type GameState a = StateT Game a
addPoints :: Int -> GameState ()
addPoints num = do
Game p <- get
put $ Game (p+num)
我希望能够简单地丢弃一些输入
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)
我想要一个看起来像这样的语法
addPoints num = do
guard evenResult
...
-- or this
addPoints num = do
guardIsEvenResult
...
如果它击中守卫,我希望它单独离开状态,并且在阻止中不做任何其他事情。
我该怎么办? MonadPlus似乎可以关闭,但我不确定我是否可以使用mzero来说“返回你在你所处的状态”。谢谢!
答案 0 :(得分:6)
导入Control.Monad.Trans.Maybe
并在StateT
之上使用MaybeT
。然后,您可以使用mzero
中止计算,或者像Kevin Ballard所说,guard condition
在condition
为False
时停止;您所要做的就是将每个块都包含在runMaybeT
中。 (请注意,您必须lift
在StateT
monad上定义的每个选项operation :: (MonadState m Game) => ...
,或更改其类型以使用具有您所需状态的任何monad,例如{{1} }。)
请注意,您可能拥有transformers
包含Control.Monad.Trans.Maybe
的包,即使您不直接使用它;包含标准monad模块(如mtl
)的Control.Monad.State
包依赖于它。
答案 1 :(得分:0)
我认为我有点充实了Pigworker对这个问题的评论。
ensure :: GameState Bool -> GameState () -> GameState ()
ensure p k = do
t <- p
when t k
addPoints num = do
ensure (evenResult num) $ do
...
哪个足够接近。我确信第三个回答更正确,但它似乎比我想要的要复杂得多。还有很多要学习的东西:)