有没有一种优雅的方法来实现此功能:`(Monad m)=>(s-> a-> m(s,b))-> s-> [a]-> m [b]`

时间:2019-02-20 14:02:36

标签: haskell functional-programming monads monad-transformers state-monad

(Monad m) => (s -> a -> m (s, b))这样的函数会根据先前的状态和当前值产生一个新状态和一个新值,这非常频繁。

我们可以使用不同的方法来实现遍历a的列表,以产生给定功能m [b]的{​​{1}}

  • 使用f :: s -> a -> m (s, b),但是代码不是特别好
  • 使用Control.Monad.foldMtraverse monad,这会更好

是否可以很好地利用现有库来将“状态定义的行为”与StateT (WriterT m)的“输出行为”分解,并在几个组合器中获得所需的遍历?

3 个答案:

答案 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,则

fa -> s -> m (b, s)十分合适。