Haskell退出状态monad早期(警卫?)

时间:2012-04-23 23:04:26

标签: haskell monads monad-transformers

我有一个代表我的应用程序游戏状态的类型,因为这个问题假装它很简单:

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来说“返回你在你所处的状态”。谢谢!

2 个答案:

答案 0 :(得分:6)

导入Control.Monad.Trans.Maybe并在StateT之上使用MaybeT。然后,您可以使用mzero中止计算,或者像Kevin Ballard所说,guard conditionconditionFalse时停止;您所要做的就是将每个块都包含在runMaybeT中。 (请注意,您必须liftStateT 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
  ...

哪个足够接近。我确信第三个回答更正确,但它似乎比我想要的要复杂得多。还有很多要学习的东西:)