对StateT,State和MonadState的困惑

时间:2017-04-16 15:34:31

标签: haskell state-monad

我之间完全混淆了

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

2 个答案:

答案 0 :(得分:13)

曾几何时,有一个State类型:

-- Not the current definition.
newtype State s a = State {runState :: s -> (a, s)}
实质上,

State s a值是处理状态并产生结果和更新状态的函数。合适的FunctorApplicativeMonad实例可以通过使元组重排需要处理隐式的(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上添加上述状态处理功能。它附带FunctorApplicativeMonad个实例,以及getput的版本。

如果mStateT 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}}变为使用MonadTransget所必需的。在这种情况下直接使用操作的一种方法是通过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的类型别名。)

StateTState monad的monad变换器。它允许你在状态中放置任意monad,从而增加了一层通用性。这对于简单的解析器是有用的,其可以使用例如StateT [Token] Maybe Result将解析表示为可能失败的有状态操作。

MonadState将情况进一步概括。有一个实例Monad m => MonadState s (StateT s m),但也有一些实例,例如允许您对StateT的monad变换器执行有状态操作的实例。所有基本状态函数(getsetmodify等)都可以与MonadState的实例一起使用。