The "obvious" way to write a monadic zygomorphism is to look at the definition for an ordinary zygomorphism, namely

zygo :: (Recursive t) => (Base t b -> b) -> (Base t (b, a) -> a) -> t -> a zygo f g = snd . cata (\x -> (f (fmap fst x), g x))

and convert it like so

zygoM :: (Recursive t, Traversable (Base t), Monad m) => (Base t b -> m b) -> (Base t (b, a) -> m a) -> t -> m a zygoM f g = fmap snd . cataM (\x -> (,) <$> f (fmap fst x) <*> g x)

But, as monads allow ordering effects, this is not always what we want. We may want f to be called after g. With that in mind, we get the second monadic zygomorphism:

zygoM' :: (Recursive t, Traversable (Base t), Monad m) => (Base t b -> m b) -> (Base t (b, a) -> m a) -> t -> m a zygoM' f g = fmap snd . cataM (\x -> do { a <- g x; b <- f (fmap fst x); pure (b, a) })

Both are now available in my recursion package.