module Control.Morphism.Apo
( apo, g_apo
, postpro_apo, g_postpro_apo
, Apo, ApoT
, distApoT
, GApo, GApoT
, distGApo, distGApoT
) where
import Control.Functor.Algebra
import Control.Functor.Extras
import Control.Functor.Fix
import Control.Monad
import Control.Monad.Either
import Control.Morphism.Ana
import Control.Morphism.Postpro
import Control.Arrow ((|||))
apo :: Functor f => GCoalgebra f (Apo f) a -> a -> FixF f
apo = g_apo outF
g_apo :: Functor f => Coalgebra f b -> GCoalgebra f (GApo b) a -> a -> FixF f
g_apo g = g_ana (distGApo g)
postpro_apo :: Functor f => GCoalgebra f (Apo f) a -> (f :~> f) -> a -> FixF f
postpro_apo = g_postpro_apo outF
g_postpro_apo :: Functor f => Coalgebra f b -> GCoalgebra f (GApo b) a -> (f :~> f) -> a -> FixF f
g_postpro_apo g = g_postpro (distGApo g)
type Apo f a = Either (FixF f) a
type ApoT f m a = EitherT (FixF f) m a
type GApo b a = Either b a
type GApoT b m a = EitherT b m a
distGApo :: Functor f => Coalgebra f b -> Dist (Either b) f
distGApo f = fmap Left . f ||| fmap Right
distGApoT :: (Functor f, Monad m) => GCoalgebra f m b -> Dist m f -> Dist (EitherT b m) f
distGApoT g k = fmap (EitherT . join) . k . liftM (fmap (liftM Left) . g ||| fmap (return . Right)) . runEitherT
distApoT :: (Functor f, Monad m) => Dist m f -> Dist (ApoT f m) f
distApoT = distGApoT (liftCoalgebra outF)