绑定计算与州monad?

Bab*_*ham 2 monads haskell state-monad

我想通过以下函数传递State monad:

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 
Run Code Online (Sandbox Code Playgroud)

当前runState传递一个State s a(implementor)和一个值(10),然后从中返回元组e1.

但是,我想将这些操作绑定在一起,例如:

state e1 >>= e2 >>= e3  
Run Code Online (Sandbox Code Playgroud)

e1将通过其State Bool Inte2,这对操作Int(通过el),然后通过它产生State Bool Inte3其中,再次,将在操作Int中该传入国.

根据指南,我发现Monad State的实例非常混乱:

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' 
Run Code Online (Sandbox Code Playgroud)

我不明白这个bind实例是做什么的,以及如何使用它来绑定e1,e2e3在一起?

Zet*_*eta 5

如果使用state :: (s -> (a, s)) -> State s ae1,你最终得到一个State Int Bool:

state e1 :: State Int Bool
Run Code Online (Sandbox Code Playgroud)

这是在一个状态(在这种情况下是一个Int)上作用的东西,并且在Bool使用该状态时产生一个.所以,如果我们要使用e1,e2e3经过对方的状态计算,我们可以用使用它们do-notation:

allThree :: State Int ()
allThree = do
  firstBool  <- state e1
  secondBool <- state e2
  thirdBool  <- state e3
  return thirdBool
Run Code Online (Sandbox Code Playgroud)

但是,如果我们忽略前两个Bools,我们可以删除绑定:

allThree :: State Int Bool
allThree = do
  state e1
  state e2
  state e3
Run Code Online (Sandbox Code Playgroud)

现在我们可以do>>和重写注释>>=.我们结束了

allThree :: State Int Bool
allThree = state e1 >> state e2 >> state e3
Run Code Online (Sandbox Code Playgroud)

至于它是如何工作的,让我们来看看 >>=

  m >>= k = state $ \s -> let (a, s') = runState m s 
                          in runState (k a) 
Run Code Online (Sandbox Code Playgroud)

m >> km >>= const k.那么让我们检查一下state e1 >> state 2:

 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'
Run Code Online (Sandbox Code Playgroud)

因此,以下术语是相同的:

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

现在,为什么我能使用的变化runState (state f)f?因为定义State很无聊:

-- simplified, modern versions use a more sophisticated approach!
newtype State s a = State { runState :: s -> (a, s) }
Run Code Online (Sandbox Code Playgroud)

也就是说,一个State完整的动作是一个状态,并返回一个新的状态.因此state功能相当简单:

state :: (s -> (a, s)) -> State s a
state = State
Run Code Online (Sandbox Code Playgroud)

既然runState (State f)f,runState (state f)也是`f'.

因此,我们可以编写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'
Run Code Online (Sandbox Code Playgroud)

请记住,>>=期望一个函数可以获取某些内容并返回另一个操作,而 >>可以用于将操作链接到彼此之后.