我有一个类型代表我的应用程序的游戏状态,对于这个问题假装它很简单,例如:
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
...
如果它击中了守卫,我希望它不去管这个状态,并且在 block 中什么都不做。
我该怎么做?使用 MonadPlus 似乎接近可能,但我不确定我是否可以使用 mzero 说“返回你在你的状态下已经拥有的东西”。谢谢!
最佳答案
进口Control.Monad.Trans.Maybe
并使用 MaybeT
在 StateT
之上.然后,您可以使用 mzero
中止计算,或者像 Kevin Ballard 所说的那样,<a href="http://hackage.haskell.org/packages/archive/base/latest/doc/html/Control-Monad.html#v:guard" rel="noreferrer noopener nofollow">guard</a> condition
如果 condition
停止是False
;您所要做的就是将每个 block 包含在 runMaybeT
中. (请注意,您要么必须 lift
您在 StateT
monad 上定义的每个选项,要么更改它们的类型以使用具有您所需状态的任何 monad,例如 operation :: (MonadState m Game) => ...
。)
请注意,您可能拥有 transformers
包装Control.Monad.Trans.Maybe
包含在,即使你没有直接使用它; mtl
包,其中包含标准的 monad 模块,如 Control.Monad.State
, 取决于它。
关于Haskell 提前退出状态 monad(守卫?),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10289486/