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.