确实放了' op在状态Monad(Haskell)中,更新实际状态还是仅返回具有新值的新状态?我的问题是,State Monad能否像一个全球变量一样使用"在一个必要的环境?并且确实放了'修改"全局变量"?
我的理解是NO它不会修改initialState,但是使用monadic接口我们可以绕过新状态b / w计算,保持初始状态"完整"。它是否正确?如果没有,请纠正我。
感谢。
答案 0 :(得分:5)
{"access_token":"ABCDEFG","expires_in":5183078}
没有什么神奇之处。你可以像这样实现它:
State
也就是说,newtype State s a = State {runState :: s -> (a, s)}
(我们认为是使用类型State s a
的状态来生成类型s
的结果的计算)只是一个函数state并返回结果和新状态。您应尝试为此定义写出a
实例以及Monad
和get
的定义。真正的定义更为通用:
put
这允许将状态添加到其他monadic计算中。也可以将状态变换器定义为“操作单元”。 Apfelmus在某个地方有一个教程。
答案 1 :(得分:4)
答案在于类型。
newtype State s a = State {runState :: s -> (a, s)}
因此,状态本质上是一个带有一个参数的函数,&#39> 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'
因此,你有一个在初始状态下运行的函数,并吐出一个值状态元组,由组合中的下一个函数处理。
现在,put
是以下功能。
put newState = State $ \s -> ((),newState)
这实际上设置了将传递给合成中的下一个函数的状态,而下游函数将看到修改后的状态。
事实上,国家monad是完全纯粹的(也就是说,没有任何东西被设置);只有传递下游的变化。换句话说,状态monad可以省去用Haskell这样的纯语言明确地携带状态的麻烦。换句话说,State monad只是提供了一个隐藏状态线程细节的接口(我认为这是WikiBooks中的所谓,或者我认为你是Haskell)。以下显示了这一点。你得到了,它将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并将其设置为新状态。
因此,您在纯粹的背景下拥有状态。希望这会有所帮助。
答案 2 :(得分:1)
首先,国家不是“全球性”的;你可以有几个不同的状态monad副本运行,每个副本都有自己独立的状态,并且它们不会相互干扰。 (事实上,这可以说是重点。)如果你希望状态对整个程序是全局的,那么你必须把整个程序放到一个状态monad中。
其次,调用put
会更改后续调用get
的结果。就这样。它不会“改变”实际值本身。比如,如果您调用get
并将结果放入某个变量,然后调用put
,则您的变量不会更改。即使状态是字典或其他东西,如果你要添加一个新密钥和put
,那么任何仍在查看字典旧版本的人仍会看到旧字典。这对州monad来说并不特别;这就是Haskell的工作方式。