haskell - 状态monad函数得到?

时间:2012-08-02 21:37:08

标签: haskell monads state-monad

根据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))

如上所述,我不再理解这一点。

所以,如果你能解释我这个奇怪的结果,那将是非常好的。 ;)

提前致谢

最好的问候,

3 个答案:

答案 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)

也许你会混淆getrunState;后者返回一个元组,其中一个组件是计算的结果,另一个组件是最终状态。事实上,你将这个元组分开来只获得(最终)状态。 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))

初始状态在运行期间未发生变化,因为getreturn都没有对其进行修改。