像(Monad m) => (s -> a -> m (s, b))
这样的函数会根据先前的状态和当前值产生一个新状态和一个新值,这非常频繁。
我们可以使用不同的方法来实现遍历a
的列表,以产生给定功能m [b]
的{{1}}
f :: s -> a -> m (s, b)
,但是代码不是特别好Control.Monad.foldM
和traverse
monad,这会更好是否可以很好地利用现有库来将“状态定义的行为”与StateT (WriterT m)
的“输出行为”分解,并在几个组合器中获得所需的遍历?
答案 0 :(得分:3)
直到废话,我们都有:
traverse @[] @(StateT s m) :: (a -> s -> m (a, s)) -> [a] -> s -> m ([b], s)
答案 1 :(得分:2)
基于Will Ness的回答,由于我有机会在代码中重新排列参数,因此我可以得到以下信息
foldAccumulate :: (Monad m) => (a -> s -> m (b, s)) -> [a] -> s -> m [b]
foldAccumulate f = evalStateT . traverse (StateT . f)
这确实是一个traverse
,带有适当的StateT m
单子,并且不需要编写任何东西,我不知道为什么我没有看到:-)。谢谢!
答案 2 :(得分:1)
简单地StateT
就可以了,
foo :: Monad m => (s -> a -> m (s, b)) -> s -> [a] -> m [b]
foo g = flip (evalStateT . mapM (StateT . f))
where
f a s = liftM swap $ g s a
swap (a,b) = (b,a) -- or import Data.Tuple
如果必须使用精确类型而不是更自然的类型flip
,则 f
和a -> s -> m (b, s)
十分合适。