我希望通过以下函数传递 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实例在做什么以及如何使用它来将e1
、e2
和e3
绑定(bind)在一起?
最佳答案
如果您在 e1
上使用 state::(s -> (a, s)) -> State s a
,您最终会得到一个 State Int bool
:
state e1 :: State Int Bool
这是对状态(在本例中为 Int
)起作用并由于使用该状态而产生 Bool
的东西。因此,如果我们想在有状态计算中依次使用 e1
、e2
和 e3
,我们可以将它们与 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 >> k
是 m >>= 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/