Как я отмечал в комментариях, сначала blu sh это похоже на работу для iterTM
, которая похожа на iterT
, за исключением того, что она выполняется в преобразователе монад по вашему выбору.
iterTM :: (Functor f, Monad m, MonadTrans t, Monad (t m)) => (f (t m a) -> t m a) -> FreeT f m a -> t m a
iterTM f (FreeT m) = do -- running in the output monad `t`
val <- lift m
case fmap (iterTM f) val of -- fold the children first
Pure x -> return x
Free y -> f y
Вы можете выбрать выходную монаду t
, но m
и a
определяются структурой данных FreeT
, которую вы сворачиваете. Для каждого слоя FreeT
, начиная с самого низа, iterTM
передает f
, полный результатов сворачивания дочерних элементов слоя в ваш обратный вызов. Вы должны решить, как обрабатывать эти результаты monadi c (выбирать между ними, упорядочивать их и т. мне больше нравится ReaderT
. (Вы не возвращаете измененное состояние из каждой итерации - просто передаете измененный параметр вниз.)
runSomeFree :: Monad m => SomeFree m a -> ReaderT (Maybe ()) m a
runSomeFree = iterTM go
where
go (SomeAct f) = ask >>= \case
Just () -> f ()
Nothing -> local (const $ Just ()) (f ())