根据State Monad的get函数提出的一个问题:
如果我跑
runState get 1
我得到了结果
(1,1)
这对我来说没问题,因为get函数将结果值设置为状态,在这种情况下状态为1.因此,(1,1)是结果。确定。
但如果我跑
runState(do {(a,b)< - get; return a})(False,0)
我得到了结果
(假,(假,0))
这个我不明白。
get函数将结果值设置为状态并保持状态不变。所以我期待的是这样的事情
((假,0),(假,0))
与此相同
runState(do {(a,b)< - get; return b})(False,0)
结果是
(0,(假,0))
如上所述,我不再理解这一点。
所以,如果你能解释我这个奇怪的结果,那将是非常好的。 ;)
提前致谢
最好的问候,
麦
答案 0 :(得分:8)
这是因为你在get
之后做了一些事情,即你return
其中一个组件。忽略newtype-wrapping,
return x = \s -> (x,s)
所以
do { (a,b) <- get; return a } === get >>= \(a,b) -> return a
扩展为
(\s -> (s,s)) >>= \(a,b) -> (\t -> (a,t))
并且(>>=)
的定义变为
\s1 -> let (r,s2) = (\s -> (s,s)) s1
in (\(a,b) -> (\t -> (a,t))) r s2
当你以初始状态(False,0)
运行时,它会展开
let (r,s2) = (\s -> (s,s)) (False,0)
~> let (r,s2) = ((False,0),(False,0))
in (\(a,b) -> (\t -> (a,t))) r s2
~> in (\(a,b) -> (\t -> (a,t))) (False,0) (False,0)
~> in (\t -> (False,t)) (False,0) -- match (a,b) with (False,0)
~> in (False, (False,0))
return b
的另一种情况类似。
答案 1 :(得分:5)
丹尼尔的答案当然是正确和完整的,所以让我试着从不同的角度回答这个问题并讨论可能的误解。
您希望
返回((False,0),(False,0))
runState (do{(a,b) <- get; return a}) (False, 0)
现在要实际获得这个预期的结果,你必须写,例如,
runState (do{(a,b) <- get; return (a,b)}) (False, 0)
(这在道德上等同于runState get (False, 0)
。
也许你会混淆get
和runState
;后者返回一个元组,其中一个组件是计算的结果,另一个组件是最终状态。事实上,你将这个元组分开来只获得(最终)状态。 get
但是有一个返回值,它只是(当前)状态,仅此而已 - 不需要解包。如果您确实将元组拆开并仅返回a
(或b
),那么这将作为完整有状态计算的结果显示出来,就像您观察到的那样。
答案 2 :(得分:1)
让我们尝试第三个答案:
get = \s -> (s,s)
确实如此,但是(在State的情况下)do-notation中的箭头只会输出值。这完全是因为这个 monad的绑定定义。
所以,你不能得到整对(s,s)
。你得到的只是第一个s
。
您提供了初始状态= (False,0)
; <-
箭头为您提供了复制的值(False,0)
,并将其绑定到(a,b)
。
然后围绕值a = False
构建状态monad。此monad将返回(a,s)
以及(False,(False,0))
。
初始状态在运行期间未发生变化,因为get
和return
都没有对其进行修改。