绑定计算与州monad?

时间:2017-02-10 18:43:32

标签: haskell monads 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 

目前runState传递State s aimplementor)和值(10),然后从e1返回元组。

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

state e1 >>= e2 >>= e3  

e1会将其State Bool Int传递给e2Int会对el(通过State Bool Int)进行操作,然后将其传递给e3 } Int再次对此传入状态的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' 进行操作。

我发现Monad State的实例非常混乱,遵循this指南:

e1

我不明白这个bind实例在做什么以及如何使用它来绑定e2e3var in = ["0:3", "1:3", "4:5", "5:6", "6:8"]

1 个答案:

答案 0 :(得分:5)

如果您在state :: (s -> (a, s)) -> State s a上使用e1,则最终会得到State Int Bool

state e1 :: State Int Bool

这是一种状态(在这种情况下为Int)并且由于使用该状态而产生Bool。因此,如果我们想要在有状态计算中相互使用e1e2e3,我们可以将它们与do一起使用 - 符号:

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

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

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

现在我们可以使用do>>重写>>= - 符号。我们最终得到了

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 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'

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

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

现在,为什么我可以将更改runState (state f)用于f?因为State的定义相当无聊:

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

也就是说,State个动作是一种状态,它会返回一个状态并返回一个新值。 state函数非常简单:

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

由于runState (State f)frunState (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'

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