我之间完全混淆了
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
答案 0 :(得分:13)
曾几何时,有一个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
,StateT s m
中的基本monad为Identity
,则为虚拟函数...
newtype Identity a = Identity {runIdentity :: a}
...我们得到的东西等同于普通的State s
。既然如此,变形金刚将State
定义为同义词......
type State s = StateT s Identity
...而不是单独的类型。
至于MonadState
,它迎合了两种不同的需求。首先,我们可以使用monad变换器机制将StateT s m
作为变换器堆栈中某些其他变换器的基本monad(任意示例:MaybeT (StateT Int IO)
)。但是,在这种情况下,来自lift
的{{1}}变为使用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
其次,如果我们想要一个实现不同于变换器中的实现的状态monad,我们可以使它成为instance Monad m => MonadState s (StateT s m) where -- etc.
instance MonadState s m => MonadState s (MaybeT m) where -- etc.
-- And so forth
的实例,这样我们就保持相同的基本操作,只要我们根据MonadState
编写类型签名,如果需要,可以更容易地更改实现。
答案 1 :(得分:4)
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
的实例一起使用。