2017-02-10 5 views
2

私は、次のような機能を通じてStateモナドを渡すために探しています:Stateモナドによる計算のバインディングは?

e1 :: Int -> (Bool, Int) 
e1 el 
    | el > 100   = (True, el) 
    | otherwise   = (False, 0) 

e2 :: Int -> (Bool, Int) 
e2 el 
    | el > 200   = (True, el) 
    | otherwise   = (False, 0) 

e3 :: Int -> (Bool, Int) 
e3 el 
    | el > 300   = (True, el) 
    | otherwise   == (False, 0) 

implementor :: State Bool Int 
implementor = state e1 ... 

main = do 
    print $ runState implementor 10 

現在runStateState s aimplementor)が渡された値(10)、その後、e1からタプルを返しています。

私は、次のような、一緒にこれらの操作をバインドしたいのですが:

state e1 >>= e2 >>= e3 

e1State Bool IntIntel経由)で動作するe2に、それはにState Bool Intを結果ズパスの通過しますe3であり、これは再び、この着信状態のIntで動作します。

私は thisガイド以下、モナド国家のインスタンスは非常に混乱見つけた

:、私はバインドのこのインスタンスがやって、どのようにe1をバインドするためにこれを使用することです理解していない

instance Monad (State s) where 
    return :: state $ \s -> (s, a)--this is returning a State which contains function (s -> (s, a)) 
    m >>= k = state $ \s -> let (a, s') = runState m s --? 
        in runState (k a) s' 

e2e3一緒に?

+1

あなたは 'state e1 >> state e2 >> state e3'を探していますか? – Zeta

+0

@Zetaわかりやすく私の質問に追加しました –

+1

「状態e1」は「状態Bool Int」ではなく「状態Int Bool」です。 – Zeta

答えて

5

あなたはe1state :: (s -> (a, s)) -> State s aを使用する場合は、あなたがState Int Boolで終わる:

state e1 :: State Int Bool 

状態の上に動作する何か(この場合はInt)であるとことを使用した結果としてBoolをもたらし状態。我々はステートフルな計算で互いの後e1e2e3を使いたいのであれば、我々はdo -notationでそれらを使用することができます。私たちは最初の2つのBool Sを無視した場合

allThree :: State Int() 
allThree = do 
    firstBool <- state e1 
    secondBool <- state e2 
    thirdBool <- state e3 
    return thirdBool 

しかし、私たちは削除することができますバインディング:

allThree :: State Int Bool 
allThree = do 
    state e1 
    state e2 
    state e3 

そして今、我々は>>>>=do -notationを書き換えることができます。私たちは、これがどのように機能するかについては

allThree :: State Int Bool 
allThree = state e1 >> state e2 >> state e3 

で終わる、のは>>=

m >>= k = state $ \s -> let (a, s') = runState m s 
          in runState (k a) 

そしてm >> km >>= const kで見てみましょう。

state e1 >> state e2 
    = state e1 >>= const (state e2) 
    = state $ \s -> let (a, s') = runState (state e1) s in runState (const (state e2) a) s' 
    -- simplify runState (state e1) s to e1 s 
    = state $ \s -> let (a, s') = e1 s in runState (const (state e2) a) s' 
    -- use "const" 
    = state $ \s -> let (a, s') = e1 s in runState (state e2) s' 
    -- again simplify runState (state e2) s' to e2 s' 
    = state $ \s -> let (a, s') = e1 s in e2 s' 

したがって、次の用語は同じです::それでは、state e1 >> state 2が何をするかチェックしてみましょう今

stateful s = runState (state e1 >> state e2) s -- use above to show that 
stateless s = let (_, s') = e1 s 
       in e2 s' 

、なぜ私はfに変更runState (state f)を使用することができましたか?Stateの定義はかなり退屈ですので:

ある
-- simplified, modern versions use a more sophisticated approach! 
newtype State s a = State { runState :: s -> (a, s) } 

State FULアクションは状態をとり、値に沿って新しいものを返すものです。

state :: (s -> (a, s)) -> State s a 
state = State 

そしてrunState (State f)以来runState (state f)も ​​`F 'で、fです:state機能は、このようにかなり単純です。

したがって、我々は少し異なるMonadインスタンスを書くことができます:

instance Monad (State s) where 
    (State e1) >>= f = State e3 
    where 
     e3 s = let (a, s') = e s 
        (State e2) = f a 
       in e2 s' 

>>が互いの後の連鎖アクションに使用することができ、一方、>>=は、何かを取り、別のアクションを返す関数を見込んで、覚えておいてください。

関連する問題