从前,有一个State类型:
-- Not the current definition.
newtype State s a = State {runState :: s -> (a, s)}
State s a 值本质上是获取状态并产生结果和更新状态的函数。合适的Functor、Applicative 和Monad 实例可以通过使元组改组需要隐式处理(a, s) 输出来以更方便的方式组合这些函数。在少数操纵状态的基本操作的帮助下......
get = State $ \s -> (s, s)
put s = State $ \_ -> ((), s)
...可以避免提及底层s -> (a, s) 类型,并编写感觉有状态的代码。
StateT s 是一个仿照State s 的单子转换器:
newtype StateT s m a = StateT {runStateT :: s -> m (a, s)}
此转换器在基本 monad m 之上添加了上述状态处理功能。它带有Functor、Applicative 和Monad 实例,以及get 和put 的版本。
如果m,基本单子,在StateT s m 是Identity,虚拟函子...
newtype Identity a = Identity {runIdentity :: a}
...我们得到的东西等同于普通的旧State s。既然如此,transformers 将State 定义为同义词...
type State s = StateT s Identity
...而不是作为一个单独的类型。
至于MonadState,它满足了两种不同的需求。首先,我们可以使用 monad 变压器机制将 StateT s m 作为变压器堆栈中其他变压器的基本 monad(任意示例:MaybeT (StateT Int IO))。但是,在这种情况下,lift 来自 MonadTrans 成为使用 get 和 put 所必需的。在这种情况下直接使用操作的一种方法是通过MonadState:它将它们作为方法提供......
-- Abridged class definition.
class Monad m => MonadState s m | m -> s where
get :: m s
put :: s -> m ()
state :: (s -> (a, s)) -> m a
... 这样我们就可以拥有涉及我们感兴趣的StateT 的任何转换器组合的实例。
instance Monad m => MonadState s (StateT s m) where -- etc.
instance MonadState s m => MonadState s (MaybeT m) where -- etc.
-- And so forth
其次,如果我们想要一个状态 monad 的实现不同于 transformers 中的实现,我们可以将其设为 MonadState 的实例,这样我们就可以保持相同的基本操作和,只要我们按照MonadState 编写类型签名,如果需要,更改实现就更容易了。