我想知道 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
这是正确的吗?
你说得非常对。
>>
实际上比您建议的更通用,但您当然可以将它与您指示的类型签名一起使用。如果您使用 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
,而这不是映射状态转换器时会发生的情况。最终结果:直觉不佳。
我认为这个维基百科页面给出了
(>>=)
对于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