答案在类型中。
newtype State s a = State {runState :: s -> (a, s)}
因此,状态实质上是一个函数,它接受一个参数's'(我们称之为状态),并返回一个元组(值,状态)。该单子可以如下实现。
instance Monad (State s) where
return a = State $ \s -> (a,s)
(State f) >>= h = State $ \s -> let (a,s') = f s
in (runState h a) s'
因此,您有一个作用于初始状态并输出值-状态元组的函数,以供合成中的下一个函数处理。
现在,
put
是以下函数。
put newState = State $ \s -> ((),newState)
这实际上设置了状态,将传递给组合中的下一个函数,下游函数将看到修改后的状态。事实上,State monad是完全纯净的(也就是说,没有任何东西被设置);只有向下游传递的内容发生了变化。换句话说,在像Haskell这样的纯语言中,State monad可以帮助你省去显式携带状态的麻烦。换句话说,State monad只提供了一个接口,隐藏了状态线程的细节(这是在WikiBooks和Learn you a Haskell中所称的)。下面的内容展示了它的作用。您可以使用get来设置value字段与state字段相同的值(请注意,我所说的“设置”是指输出而不是变量)。put通过传递给它的值获取状态,将其增加并使用此新值设置状态。
-- execState :: State s a -> s -> s
let x = get >>= \x -> put (x+10)
execState x 10
上面的输出结果为20。
现在,让我们做以下操作。
execState (x >> x) 10
这将会输出30。第一个
x
通过put方法将状态设置为20。第二个
x
现在使用这个状态。此时的
get
将状态传递到值字段,现在它的值为20。现在,我们的put方法将获取这个值,增加10并将其设置为新状态。
因此,在纯净的上下文中,您拥有状态。希望这可以帮助您。