是否有一种优雅的方式来实现这个功能:`(Monad m)=>(s - > a - > m(s,b)) - > s - > [a] - > m [b]`

问题描述 投票:1回答:3

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

我们可以使用不同的方法来实现a列表的遍历,以产生m [b]给定函数f :: s -> a -> m (s, b)

  • 使用Control.Monad.foldM但代码不是特别好
  • 使用traverseStateT (WriterT m) monad,这有点好

有没有很好地利用现有的库来分解f的“输出行为”的“状态定义的行为”,并在几个组合器中获得所需的遍历?

haskell functional-programming monads monad-transformers state-monad
3个回答
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

如果你必须使用你的确切类型而不是更自然的类型flipfa -> s -> m (b, s)使这些部分合适。


3
投票

直到newtype废话,我们有:

traverse @[] @(StateT s m) :: (a -> s -> m (a, s)) -> [a] -> s -> m ([b], s)

2
投票

根据Will Ness的回答,因为我有机会在我的代码中重新排列参数,我可以得到以下结果

foldAccumulate :: (Monad m) => (a -> s -> m (b, s)) -> [a] -> s -> m [b]
foldAccumulate f = evalStateT . traverse (StateT . f)

这确实是一个traverse与适当的StateT m monad,并且没有必要写任何东西,我不知道为什么我没有看到:-)。谢谢!

© www.soinside.com 2019 - 2024. All rights reserved.