对StateT,State和MonadState的困惑

hgi*_*sel 8 haskell state-monad

我完全混淆了

newtype StateT s m a = StateT {runStateT :: s -> m (a, s)}
Run Code Online (Sandbox Code Playgroud)

type State s = StateT s Identity
Run Code Online (Sandbox Code Playgroud)

class Monad m => MonadState s m | m -> s
Run Code Online (Sandbox Code Playgroud)

dup*_*ode 16

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

-- Not the current definition.
newtype State s a = State {runState :: s -> (a, s)}
Run Code Online (Sandbox Code Playgroud)

State s a值本质上是取状态并产生结果和更新状态的函数.通过使元组改组需要隐含地处理输出Functor,合适的ApplicativeMonad实例使得以更方便的方式组成这些函数成为可能(a, s).借助操纵国家的少数基本操作......

get = State $ \s -> (s, s)
put s = State $ \_ -> ((), s)
Run Code Online (Sandbox Code Playgroud)

...可以避免提及底层s -> (a, s)类型,并编写感觉有状态的代码.

StateT s是一个monad变压器图案后State s:

newtype StateT s m a = StateT {runStateT :: s -> m (a, s)}
Run Code Online (Sandbox Code Playgroud)

该变换器在基本monad上添加了上述状态处理能力m.它配备了Functor,ApplicativeMonad实例,以及版本getput.

如果m,基地单子,在StateT s mIS Identity中,伪仿...

newtype Identity a = Identity {runIdentity :: a}
Run Code Online (Sandbox Code Playgroud)

...我们得到的东西相当于普通的旧东西State s.既然如此,变形金刚定义State为同义词......

type State s = StateT s Identity
Run Code Online (Sandbox Code Playgroud)

......而不是单独的类型.

至于MonadState它,它迎合了两种不同的需求.首先,我们可以使用monad变压器机器StateT s m作为变压器堆栈中其他变压器的基础单元(任意示例:) MaybeT (StateT Int IO).在这种情况下,虽然,liftMonadTrans必要使用getput.在这种情况下直接使用操作的一种方法是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
Run Code Online (Sandbox Code Playgroud)

......这样我们就可以拥有涉及StateT我们感兴趣的任何变压器组合的实例.

instance Monad m => MonadState s (StateT s m) where -- etc.
instance MonadState s m => MonadState s (MaybeT m) where -- etc.
-- And so forth
Run Code Online (Sandbox Code Playgroud)

其次,如果我们想要一个实现与变换器中的实现不同的状态monad ,我们可以使它成为一个实例MonadState,这样我们就可以保持相同的基本操作,只要我们写类型签名MonadState,就有了如果需要,更容易更改实现.


zbw*_*zbw 6

State用于您的正常状态单子。这是三者中最简单的。(在一些较旧的教程中,您可能会看到使用State构造函数,但这已被替换为state函数,因为State s现在是 的类型别名StateT s Identity。)

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

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