haskell - 将计算与状态单子(monad)绑定(bind)?

标签 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 a (implementor)和一个值 (10),然后从 返回元组e1.

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

state e1 >>= e2 >>= e3  

e1 会将其 State Bool Int 传递给 e2,后者将对 Int 进行操作(通过 el),然后将其生成的 State Bool Int 传递给 e3,后者将再次对这里的 Int 进行操作传入状态。

我发现 Monad State 的实例非常困惑,如下 this指南:

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' 

我不明白这个bind实例在做什么以及如何使用它来将e1e2e3绑定(bind)在一起?

最佳答案

如果您在 e1 上使用 state::(s -> (a, s)) -> State s a,您最终会得到一个 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,我们可以删除绑定(bind):

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 :: (s -> (a, s)) -> State s a
state = State

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

请记住,>>= 期望一个函数接受某些内容并返回另一个操作,而 >> 可用于将操作相互链接。

关于haskell - 将计算与状态单子(monad)绑定(bind)?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42166512/

相关文章:

list - 使用冒泡排序按长度对列表中的列表进行排序 - Haskell

haskell - 不可判定的函数依赖

haskell - 变量的Lambda演算变化及应用问题

haskell - 为什么 `do` block 中的类型在下一行匹配,但在同一行不匹配?

haskell - 为什么这个 haskell 代码没有终止

Haskell:在 FreeMonad 解释器中使用 MonadState 进行内存

Haskell:如何在 State monad 之上编写交互式解释器?

haskell - foldl/foldr 查询

haskell - MaybeT monad 中没有任何内容 : more concise way?

haskell - 如何在 ADT 或记录语法上使用 Monadic 绑定(bind)运算符