Есть ли элегантный способ реализовать эту функцию: `(Monad m) => (s -> a -> m (s, b)) -> s -> [a] -> m [b]` - PullRequest
0 голосов
/ 20 февраля 2019

Функция, подобная (Monad m) => (s -> a -> m (s, b)), создающая новое состояние и новое значение на основе предыдущего состояния и текущего значения, довольно часто.

Мы можем использовать различные подходы для реализации обхода списка a, чтобы получить m [b] для данной функции f :: s -> a -> m (s, b)

  • , используя Control.Monad.foldM, но кодне очень хорошо
  • с использованием traverse и монадой StateT (WriterT m), что немного лучше

Есть ли хорошее применение существующим библиотекам для разложения "определенного государством"поведение "с" выходным поведением "f и получить желаемый обход в нескольких комбинаторах?

Ответы [ 3 ]

0 голосов
/ 20 февраля 2019

Обычного 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).

0 голосов
/ 20 февраля 2019

Основываясь на ответе Уилла Несса и, поскольку у меня есть возможность переставить аргументы в моем коде, я могу получить следующее

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

, которое действительно является traverse с соответствующей монадой StateT m, ине нужно ничего писать, я не знаю, почему я этого не видел :-).Спасибо!

0 голосов
/ 20 февраля 2019

Чепуха нового типа, у нас есть:

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