use*_*543 3 haskell state-monad
'将'操作'置于Monad(Haskell)状态,更新实际状态还是仅返回具有新值的新状态?我的问题是,State Monad可以像一个"全局变量"一样在必要的环境中使用吗?'put'是否修改了"全局变量"?
我的理解是NO它不修改initialState,但是使用monadic接口我们可以传递新的状态b/w计算,使初始状态"完整".它是否正确?如果没有,请纠正我.
谢谢.
小智 6
答案在于类型。
newtype State s a = State {runState :: s -> (a, s)}
Run Code Online (Sandbox Code Playgroud)
因此,状态本质上是一个函数,它接受一个参数“s”(我们称之为状态),并返回一个元组(值,状态)。monad 实现如下
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'
Run Code Online (Sandbox Code Playgroud)
因此,您有一个函数,它对初始状态进行操作并输出一个值状态元组,以供组合中的下一个函数处理。
现在,put是以下功能。
put newState = State $ \s -> ((),newState)
Run Code Online (Sandbox Code Playgroud)
这实质上设置了将传递给组合中的下一个函数的状态,并且下游函数将看到修改后的状态。
事实上,State monad 是完全纯净的(即没有设置任何东西);只有传递到下游的东西才会改变。换句话说,State monad 省去了用像 Haskell 这样的纯语言显式地携带状态的麻烦。换句话说,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
Run Code Online (Sandbox Code Playgroud)
以上输出20。
现在,让我们执行以下操作。
execState (x >> x) 10
Run Code Online (Sandbox Code Playgroud)
这将给出 30 的输出。第一个x通过 put 将状态设置为 20。这现在被第二个使用x。在get这个点集的状态时,它传递到值字段,也就是现在的20现在,我们放就会获得这个值,由10增加它并将其设置为新的状态。
因此,您在纯上下文中拥有状态。希望这可以帮助。
什么都没有什么神奇之处State.你可以像这样实现它:
newtype State s a = State {runState :: s -> (a, s)}
Run Code Online (Sandbox Code Playgroud)
也就是说,a State s a(我们认为是使用类型状态s来生成类型结果的计算a)只是一个获取状态并返回结果和新状态的函数.你应该尝试写出来的Monad实例和定义get,并put就此定义.真正的定义更为通用:
type State s = StateT s Identity
newtype Identity a = Identity a
newtype StateT s m a = StateT {runStateT :: s -> m (a, s)}
Run Code Online (Sandbox Code Playgroud)
这允许将状态添加到其他monadic计算中.也可以将状态变换器定义为"操作单元".Apfelmus有一个关于那些地方的教程.