然后状态 Monad (>>)

问题描述 投票:0回答:2

我想知道 Haskell 状态 monad 的

>>
的定义。

据我猜测,它会将一种状态传递到另一种状态:

(>>) :: State s a -> State s b -> State s b
State a >> State b = State $ \x -> b $ snd ( a x )

State a >> State b = State $ b . snd . a

这是正确的吗?

haskell monads state-monad
2个回答
4
投票

你说得非常对。

>>
实际上比您建议的更通用,但您当然可以将它与您指示的类型签名一起使用。如果您使用
State
来自它的平常家,
Control.Monad.Trans.State.Strict
,或者它的家外之家,
Control.Monad.State.Strict
State
实际上只是一个类型同义词:

type State s = StateT s Identity

其中

Identity
来自
Data.Functor.Identity
并定义

newtype Identity x = Identity x

StateT
已定义

newtype StateT s m a = StateT {runStateT :: s -> m (a, s)}

所以

State s a
只是一个新型包装器

s -> Identity (a, s)

这本质上与你想象的定义相同,但它允许

State s
monad 转换器
StateT s
兼容,用于向任意
Monad
添加状态。

instance Monad m => Monad (StateT s m) where
  return a = StateT $ \s -> return (a, s)
  StateT g >>= f = StateT $ \s -> g s >>= \(r,s') -> runStateT (f r) s'

所以

  StateT g >> StateT h = StateT $ \s -> g s >>= \(_,s') -> h s'

                       = StateT $ \s -> h $ snd $ runIdentity (g s)
                       = StateT $ h . snd . runIdentity . g

不相关的旁注

StateT
的定义让我很恼火,因为在我看来,它把对的元素放在了错误的顺序。为什么错了?因为映射
(a, s)
会改变
s
,同时保留
a
,而这不是映射状态转换器时会发生的情况。最终结果:直觉不佳。


2
投票

我认为这个维基百科页面给出了

(>>=)
对于
State
单子的定义:

m >>= f = \r -> let (x, s) = m r in (f x) s

由于

(>>)
是按照
(>>=)
实现的,如下:

m >> k = m >>= \_ -> k

可以导出状态单子的

(>>)
的定义:

m >> k = \r -> let (x, s) = m r in ((\_ -> k) x) s

或者消除噪音时:

m >> k = \r -> let (x, s) = m r in k s

现在由于

x
in
子句中不起作用,你确实可以使用
snd
来得到
s
,因此可以重写为:

m >> k = \r -> k $ snd m r
© www.soinside.com 2019 - 2024. All rights reserved.