注意:camccann 的答案比我的要好,但我的方法略有不同,并给出了如何评估状态单子的示例,因此我将其留在这里以供参考。
getAverage
我们可以通过删除函数的类型签名和参数 ( )来尝试找出问题c
所在:
getAverage s=get >>= \s0 -> let (x,s1) =media s s0
in put s1 >> return x
这仍然无法编译,因为我们正在尝试put
一些没有正确类型的东西:s1
是 a Double
,而不是 a MyState
。这很容易解决:
getAverage s=get >>= \s0 -> let s1@(x,_) =media s s0
in put s1 >> return x
我们也可以let
保持模式不变,只是说put (x,s1)
:我这样做是为了让我们s1
的类型与s0
.
这编译,所以现在我们可以修复类型签名。如果我们向 GHCi 询问类型,它会返回以下内容:
getAverage :: (Fractional t, MonadState (t, t) m) => t -> m t
Double
是 的一个实例Fractional
,并且State MyState
是 的一个实例MonadState (Double, Double)
,因此我们可以使用与您的原始类型非常相似的东西getAverage
:
getAverage :: Double -> State MyState Double
这个函数并没有真正“得到”平均值:它在添加一个新值后更新它,所以让我们适当地重命名它:
updateAverage :: Double -> State MyState Double
updateAverage s=get >>= \s0 -> let s1@(x,_) =media s s0
in put s1 >> return x
现在我们可以定义一个getAverages
函数,它接受一个Double
s 列表,运行它们updateAverage
,并在每一步返回一个中间平均值列表:
getAverages :: [Double] -> [Double]
getAverages ss = evalState (mapM updateAverage ss) (0, 0)
这符合我们的预期:
*Main> getAverages [1..10]
[1.0,1.5,2.0,2.5,3.0,3.5,4.0,4.5,5.0,5.5]
请注意,要对State
monad 做任何有用的事情,您总是必须使用evalState
(或密切相关的runState
and execState
)。