3

我有一个代表我的应用程序游戏状态的类型,对于这个问题,假设它很简单,例如:

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 来表示“返回你已经拥有的状态”。谢谢!

4

2 回答 2

7

在. Control.Monad.Trans.Maybe_ MaybeT_ StateT然后,您可以使用mzero中止计算,或者像 Kevin Ballard 所说的那样,如果is 则guard condition停止;您所要做的就是将每个块包含在. (请注意,您要么必须在 monad 上定义的每个选项,要么更改它们的类型以使用具有所需状态的任何 monad,例如。)conditionFalserunMaybeTliftStateToperation :: (MonadState m Game) => ...

请注意,即使您不直接使用它,您也可能拥有其中包含的transformers包;包含标准 monad 模块(如)Control.Monad.Trans.Maybe的包依赖于它。mtlControl.Monad.State

于 2012-04-23T23:11:44.073 回答
0

我是在充实养猪工人对这个问题的评论。

ensure :: GameState Bool -> GameState () -> GameState ()
ensure p k = do 
  t <- p 
  when t k

addPoints num = do
  ensure (evenResult num) $ do
  ...

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

于 2012-04-24T15:40:32.073 回答