2017-04-16 95 views
1

我心乱如麻混淆StateT,国家和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 
+4

你确切的问题是什么?你想要完成什么类型​​的目标?你的困惑来自哪里?你不知道'newtype','type'和'class'是什么?如果你只是不理解这些结构,那么只需阅读一些Haskell教程。 StackOverflow是针对特定问题的。 – Shersh

+1

问题是...? :) – Alec

回答

4

从前,有一个State类型:

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

State s a值是,在本质上,采取的状态,并产生一个结果,并更新状态的功能。合适的Functor,ApplicativeMonad实例使得有可能通过使得元组混排需要处理输出隐式来更方便地组合这些函数。与操作状态操作的几个基本的帮助...

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)} 

这种变压器的顶上添加碱单子,m上述状态的处理能力。它附带Functor,ApplicativeMonad实例,以及getput的版本。

如果m,基地单子,在StateT s mIdentity,伪仿...

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))。在这种情况下,使用getput时,需要liftMonadTrans。直接在这样的情况下使用该业务的一种方式是通过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 

其次,如果我们希望有一个比变压器不同的实现的状态单子,我们可以把它的MonadState一个实例,让我们保持相同的基本操作,并为只要我们写类型签名根据MonadState计算,如果需要,可以更容易地更改实现。

2

State是你的正常状态单子。这是三者中最简单的。 (在一些老的教程,你可以看到使用State构造,但这已经被替换为state功能,因为State s现在是StateT s Identity一个类型别名。)

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

MonadState将情况概括得更远。有一个实例Monad m => MonadState s (StateT s m),但也有一些实例,如允许您在单粒变换器StateT上执行有状态操作的实例。所有基本状态功能(getset,modify等)可与MonadState的实例一起使用。