2012-04-23 4 views
3

は、私はこの質問のために、自分のアプリケーションのためのゲームの状態を表しているタイプは、それをふりをしているのような単純なものです。Haskellの出口ステートモナド早く(?ガード)

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でをcloseとすることができますが、私はmzeroを使用して "あなたの状態で既に持っているものを返す"と言うことはできません。ありがとう!

+0

'StateT'はすでに' MonadPlus'です。 'Control.Monad.guard'を使ってみましたか? –

+0

@KevinBallard: 'StateT s m'は' m'があれば 'MonadPlus'です。インスタンスは 'mzero'と' mplus'を一レベル上げるだけです。 – ehird

+2

あなたはControl.Monad.when yer manですか?確かに、「Bool」を作る計算ではなく、「Bool」の値が必要なときは迷惑です。しかしローマは一日で焼かれなかった。あなたの 'test'が' m Bool'にある場合、 '(test >> =)と書くことができます。 「$ action」のときにたわごとのような混乱のためにフリップします。 – pigworker

答えて

6

Control.Monad.Trans.Maybeをインポートし、MaybeTStateTの上に使用します。次に、mzeroを使用して計算を中止するか、conditionFalseの場合、Kevin Ballardの説明のように、guard conditionを停止することができます。それぞれのブロックをrunMaybeTに囲むだけで済みます。あなたはおそらくtransformersを持っている(あなたがliftに、あなたのStateTモナドの上に定義したすべてのオプションがあるでしょうに留意されたい、またはあなたがoperation :: (MonadState m Game) => ...のように、必要な状態で任意のモナドで動作するように彼らの種類を変更します。)

注意あなたが直接使用していない場合でも、Control.Monad.Trans.Maybeが含まれているパッケージ。 Control.Monad.Stateのような標準モナドモジュールを含むmtlパッケージはそれに依存します。

0

私はだと思います。私はこの問題に関するpigworkerのコメントを洗い出しています。

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

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

これは十分に近いものです。私は確かにあなたの答えはより正しいですが、それはまた、私が望むよりもはるかに複雑に思えます。そんなにまだ学ぶこと:)

+0

また、私は '確実:: ::(Game - > Bool) - > GameState() - > GameState()'と私のすべての述語関数を 'whatever :: Game - > Bool'として' GameState Bool' –