将计算与 State monad 绑定?
Binding computations with the 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
.
返回元组
不过我想把这些操作绑定在一起,比如:
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
绑定在一起?
如果你在 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
,我们可以删除绑定:
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
ful 动作需要一个状态,returns 一个新的状态和值。 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'
请记住,>>=
需要一个接受某项操作的函数和 returns 另一个操作,而 >>
可用于将操作串联起来。
我希望通过以下函数传递一个 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
.
不过我想把这些操作绑定在一起,比如:
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
绑定在一起?
如果你在 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
,我们可以删除绑定:
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
ful 动作需要一个状态,returns 一个新的状态和值。 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'
请记住,>>=
需要一个接受某项操作的函数和 returns 另一个操作,而 >>
可用于将操作串联起来。