关于 StateT、State 和 MonadState 的困惑
Confusion about StateT, State and MonadState
我一头雾水
newtype StateT s m a = StateT {runStateT :: s -> m (a, s)}
和
type State s = StateT s Identity
和
class Monad m => MonadState s m | m -> s
State
适用于您的正常状态 monad。这是三者中最简单的。 (在一些较早的教程中,您可能会看到 State
构造函数的使用,但这已被 state
函数取代,因为 State s
现在是 StateT s Identity
的类型别名.)
StateT
是 State
monad 的 monad 转换器。它通过允许您在状态中放置任意 monad 来增加一层通用性。这对于简单的解析器很有用,它可以使用例如StateT [Token] Maybe Result
将解析表示为可能会失败的有状态操作。
MonadState
进一步概括了这种情况。有一个实例 Monad m => MonadState s (StateT s m)
,但也有一些实例,例如允许您对 StateT
的 monad 转换器执行有状态操作的实例。所有基本状态函数(get
、set
、modify
等)都可以与 MonadState
.
的实例一起使用
从前,有一个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
:
之后模式化的 monad 转换器
newtype StateT s m a = StateT {runStateT :: s -> m (a, s)}
此转换器在基础 monad 上添加了上述状态处理功能,m
。它带有 Functor
、Applicative
和 Monad
实例,以及 get
和 put
.
的版本
如果 m
,基础 monad,在 StateT s m
中是 Identity
,虚拟函子...
newtype Identity a = Identity {runIdentity :: a}
...我们得到了相当于普通旧 State s
的东西。既然如此,transformers 将 State
定义为同义词...
type State s = StateT s Identity
...而不是作为一个单独的类型。
至于MonadState
,它迎合了两种不同的需求。首先,我们可以使用 monad transformers 机制将 StateT s m
作为 transformer 堆栈中其他一些 transformer 的基础 monad(任意示例:MaybeT (StateT Int IO)
)。但是,在那种情况下,MonadTrans
中的 lift
变得有必要使用 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
编写类型签名,就可以在需要时更轻松地更改实现。
我一头雾水
newtype StateT s m a = StateT {runStateT :: s -> m (a, s)}
和
type State s = StateT s Identity
和
class Monad m => MonadState s m | m -> s
State
适用于您的正常状态 monad。这是三者中最简单的。 (在一些较早的教程中,您可能会看到 State
构造函数的使用,但这已被 state
函数取代,因为 State s
现在是 StateT s Identity
的类型别名.)
StateT
是 State
monad 的 monad 转换器。它通过允许您在状态中放置任意 monad 来增加一层通用性。这对于简单的解析器很有用,它可以使用例如StateT [Token] Maybe Result
将解析表示为可能会失败的有状态操作。
MonadState
进一步概括了这种情况。有一个实例 Monad m => MonadState s (StateT s m)
,但也有一些实例,例如允许您对 StateT
的 monad 转换器执行有状态操作的实例。所有基本状态函数(get
、set
、modify
等)都可以与 MonadState
.
从前,有一个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
,基础 monad,在 StateT s m
中是 Identity
,虚拟函子...
newtype Identity a = Identity {runIdentity :: a}
...我们得到了相当于普通旧 State s
的东西。既然如此,transformers 将 State
定义为同义词...
type State s = StateT s Identity
...而不是作为一个单独的类型。
至于MonadState
,它迎合了两种不同的需求。首先,我们可以使用 monad transformers 机制将 StateT s m
作为 transformer 堆栈中其他一些 transformer 的基础 monad(任意示例:MaybeT (StateT Int IO)
)。但是,在那种情况下,MonadTrans
中的 lift
变得有必要使用 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
编写类型签名,就可以在需要时更轻松地更改实现。