2016-04-13 3 views
2

私はいくつかのモナドアクションを持っています:Stateアクションのいくつかは、現在の状態と任意選択で結果を生成する他の入力に基づいて決定を行います。この2つのタイプのアクションはお互いを呼び出します。ステートとステートトランスフォーマーのアクションの作成

StateStateT Maybeで2つのアクションタイプをモデル化しました。次の(考案された)例は私の現在のアプローチを示しています。

{-# LANGUAGE MultiWayIf #-} 

import Control.Monad (guard) 
import Control.Monad.Identity (runIdentity) 
import Control.Monad.Trans.State 

type Producer  = Int -> State [Int] Int 
type MaybeProducer = Int -> StateT [Int] Maybe Int 

produce :: Producer 
produce n 
    | n <= 0 = return 0 

    | otherwise = do accum <- get 
        let mRes = runStateT (maybeProduce n) accum 

        if | Just res <- mRes -> StateT $ const (return res) 
         | otherwise  -> do res <- produce (n - 1) 
               return $ res + n 

maybeProduce :: MaybeProducer 
maybeProduce n = do guard $ odd n 
        modify (n:) 

        mapStateT (return . runIdentity) $ 
         do res <- produce (n - 1) 
          return $ res + n 

私はアクションチェック自体は非常に複雑(仕事の80%)であるので(したがって、単純なステートアクションにそれらを変換する)からチェックを分離して考えると、アクションに必要なバインディングを提供しています。 StateのアクションをStateT Maybeに昇格させたくないのは、不正確なモデルになっているからです。

私が紛失しているより良いまたはより多くのeleganの方法がありますか?特に私はmapStateT/runStateTデュオが好きではありませんが、必要なようです。

PS:私は例が実際にWriterですけど、私はより良い本物の場合、それは不正確をもたらすので、私は、どちらかStateT MaybeState行動を促進したくない

+2

'mapStateT'は完全に上手くIMOです。私はちょうど 'ちょうど使用するだろう。 runIdentity'を引数として使用します。 – arrowd

+0

おおよそ同じ質問(理論的だが):http://stackoverflow.com/questions/4138671/combining-statet-and-state-monads – gcnew

答えて

1

を反映するためにStateを使用モデル。

「プロモーション」とはどういう意味ですか?私はあなたが意味するこれらのどの伝えることはできません。その種類は、彼らがすべてでMaybeに依存していないにもかかわらず、今StateT Maybeなるよう

    Stateアクションの定義を書き換え
  1. State s aStateT s Maybe aに変換するアダプタ関数を使用します。

私は(1)拒絶に同意するが、私にはどちらかを意味している:

  • ゴー(2)のために。便利なツールの1つは、mmorph libraryblog entry)です。
  • State s aのアクションを書き換えてMonad m => StateT s m aを使用してください。第2のケースで

、型は、任意のモナドm互換であるが、コードは、任意の特定の塩基モナドを想定することができ、あなたがState s aと同じ純度を得ません。

私はmmorphをショットします。注:

  • State s a =;
  • hoist generalize :: (MFunctor t, Monad m) => t Identity a -> t m a;
  • それはhoist generalize :: State s a -> StateT s Maybe aに特化しています。

EDIT:それは、これらの逆関数によって与えられState s aforall m. StateT s m aタイプの間の同型があることは何も価値がある:

{-# LANGUAGE RankNTypes #-} 

import Control.Monad.Morph 
import Control.Monad.Trans 
import Control.Monad.Trans.State 
import Control.Monad.Identity 

fwd :: (MFunctor t, Monad m) => t Identity a -> t m a 
fwd = hoist generalize 

-- The `forall` in the signature forbids callers from demanding any 
-- specific choice of type for `m`, which allows *us* to choose 
-- `Identity` for `m` here. 
bck :: MFunctor t => (forall m. t m a) -> t Identity a 
bck = hoist generalize 

のでMonad m => StateT s m ammorphソリューションは、効果的に、あります、 同じ。私はここでmmorphを使用することを好む。

+0

はい、私は(1)を参照していた "促進する"。 'Monad m => StateT s m a'はまあまあではありませんが、APIスタンドポイントから少し誤解を感じます。もちろん、それはまったく意味があります - 「私は内モナドのタイプに依存しません」。 'mmorph'は仕事のための正しいツールのように見える、ありがとう。 – gcnew

+0

"Monad m => StateT s m a'は厄介ではありませんが、APIスタンドポイントから少し誤解を感じます。私はそれがはっきりしていないことに同意するが、厳密に言えば、誤解を招くものではないと言っているだろう。なぜなら、タイプは**状態にある同型であるからである。回答を編集してください。 –

関連する問題