有没有一种优雅的方式来实现这个功能:`(Monad m) => (s -> a -> m (s, b)) -> s -> [a] -> m [b]`
Is there an elegant way to implement this function: `(Monad m) => (s -> a -> m (s, b)) -> s -> [a] -> m [b]`
像(Monad m) => (s -> a -> m (s, b))
这样的函数根据先前的状态和当前值产生新的状态和新的值是非常频繁的。
我们可以使用不同的方法来实现 a
列表的遍历,以在给定函数 f :: s -> a -> m (s, b)
的情况下生成 m [b]
- 使用
Control.Monad.foldM
但是代码不是特别好
- 使用
traverse
和一个 StateT (WriterT m)
monad,这样更好一些
是否可以很好地利用现有库将 "state-defined behaviour" 分解为 f
的 "output behaviour" 并在几个组合器中获得所需的遍历?
到废话为止,我们有:
traverse @[] @(StateT s m) :: (a -> s -> m (a, s)) -> [a] -> s -> m ([b], s)
普通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)
。
根据 Will Ness 的回答,因为我有机会在我的代码中重新排列参数,所以我可以得到以下结果
foldAccumulate :: (Monad m) => (a -> s -> m (b, s)) -> [a] -> s -> m [b]
foldAccumulate f = evalStateT . traverse (StateT . f)
这确实是一个 traverse
和适当的 StateT m
monad,不需要写任何东西,我不知道为什么我没有看到它:-)。谢谢!
像(Monad m) => (s -> a -> m (s, b))
这样的函数根据先前的状态和当前值产生新的状态和新的值是非常频繁的。
我们可以使用不同的方法来实现 a
列表的遍历,以在给定函数 f :: s -> a -> m (s, b)
m [b]
- 使用
Control.Monad.foldM
但是代码不是特别好 - 使用
traverse
和一个StateT (WriterT m)
monad,这样更好一些
是否可以很好地利用现有库将 "state-defined behaviour" 分解为 f
的 "output behaviour" 并在几个组合器中获得所需的遍历?
到废话为止,我们有:
traverse @[] @(StateT s m) :: (a -> s -> m (a, s)) -> [a] -> s -> m ([b], s)
普通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)
。
根据 Will Ness 的回答,因为我有机会在我的代码中重新排列参数,所以我可以得到以下结果
foldAccumulate :: (Monad m) => (a -> s -> m (b, s)) -> [a] -> s -> m [b]
foldAccumulate f = evalStateT . traverse (StateT . f)
这确实是一个 traverse
和适当的 StateT m
monad,不需要写任何东西,我不知道为什么我没有看到它:-)。谢谢!