{-# LANGUAGE AllowAmbiguousTypes #-}
{-# LANGUAGE DeriveFoldable #-}
{-# LANGUAGE DeriveFunctor #-}
{-# LANGUAGE DeriveTraversable #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE ScopedTypeVariables #-}
module Data.Functor.Foldable.Monadic
(
cataM
, preproM
, paraM
, zygoM
, histoM, histoM'
, dynaM, dynaM', dynaM''
, anaM
, postproM
, apoM
, cozygoM
, futuM, futuM'
, codynaM, codynaM', codynaM''
, hyloM, metaM
, hyloM', metaM'
, chronoM, cochronoM
, chronoM'
, gcataM, gcataM'
, mutuM, comutuM
, mutuM', comutuM'
, cascadeM, iterateM
) where
import Control.Comonad (Comonad (..))
import Control.Comonad.Cofree (Cofree (..))
import qualified Control.Comonad.Trans.Cofree as CF (CofreeF (..))
import Control.Monad ((<=<), liftM, liftM2)
import Control.Monad.Free (Free (..))
import qualified Control.Monad.Trans.Free as FR (FreeF (..))
import Data.Functor.Foldable (Recursive (..), Corecursive (..), Base)
cataM :: (Monad m, Traversable (Base t), Recursive t)
=> (Base t a -> m a)
-> t -> m a
cataM phi = h
where h = phi <=< mapM h . project
anaM :: (Monad m, Traversable (Base t), Corecursive t)
=> (a -> m (Base t a))
-> a -> m t
anaM psi = h
where h = return . embed <=< mapM h <=< psi
paraM :: (Monad m, Traversable (Base t), Recursive t)
=> (Base t (t, a) -> m a)
-> t -> m a
paraM phi = h
where h = phi <=< mapM (liftM2 (,) <$> return <*> h) . project
apoM :: (Monad m, Traversable (Base t), Corecursive t)
=> (a -> m (Base t (Either t a)))
-> a -> m t
apoM psi = h
where h = return . embed <=< mapM (either return h) <=< psi
histoM :: (Monad m, Traversable (Base t), Recursive t)
=> (Base t (Cofree (Base t) a) -> m a)
-> t -> m a
histoM phi = h
where h = phi <=< mapM f . project
f = anaM (liftM2 (CF.:<) <$> h <*> return . project)
histoM' :: (Monad m, Traversable (Base t), Recursive t)
=> (Base t (Cofree (Base t) a) -> m a)
-> t -> m a
histoM' phi = return . extract <=< cataM f
where f = liftM2 (:<) <$> phi <*> return
futuM :: (Monad m, Traversable (Base t), Corecursive t)
=> (a -> m (Base t (Free (Base t) a)))
-> a -> m t
futuM psi = h
where h = return . embed <=< mapM f <=< psi
f = cataM $ \case
FR.Pure a -> h a
FR.Free fb -> return (embed fb)
futuM' :: (Monad m, Traversable (Base t), Corecursive t)
=> (a -> m (Base t (Free (Base t) a)))
-> a -> m t
futuM' psi = anaM f . Pure
where f (Pure a) = psi a
f (Free fb) = return fb
zygoM :: (Monad m, Traversable (Base t), Recursive t)
=> (Base t a -> m a)
-> (Base t (a, b) -> m b)
-> t -> m b
zygoM f phi = return . snd <=< cataM g
where g = liftM2 (,) <$> (f <=< return . fmap fst) <*> phi
cozygoM :: (Monad m, Traversable (Base t), Corecursive t)
=> (a -> m (Base t a))
-> (b -> m (Base t (Either a b)))
-> b -> m t
cozygoM f psi = anaM g . Right
where g = either (return . fmap Left <=< f) psi
hyloM :: (Monad m, Traversable t)
=> (t b -> m b)
-> (a -> m (t a))
-> a -> m b
hyloM phi psi = h
where h = phi <=< mapM h <=< psi
hyloM' :: forall m t a b. (Monad m, Traversable (Base t), Recursive t, Corecursive t)
=> (Base t b -> m b)
-> (a -> m (Base t a))
-> a -> m b
hyloM' phi psi = (cataM phi :: t -> m b) <=< (anaM psi :: a -> m t)
metaM :: (Monad m, Traversable (Base t), Recursive s, Corecursive t, Base s ~ Base t)
=> (Base t t -> m t)
-> (s -> m (Base s s))
-> s -> m t
metaM _phi _psi = h
where h = return . embed <=< mapM h . project
metaM' :: (Monad m, Corecursive c, Traversable (Base c), Traversable (Base t), Recursive t)
=> (Base t a -> m a)
-> (a -> m (Base c a))
-> t -> m c
metaM' phi psi = anaM psi <=< cataM phi
chronoM' :: (Monad m, Traversable t)
=> (t (Cofree t b) -> m b)
-> (a -> m (t (Free t a)))
-> a -> m b
chronoM' phi psi = return . extract <=< hyloM f g . Pure
where f = liftM2 (:<) <$> phi <*> return
g (Pure a) = psi a
g (Free fb) = return fb
chronoM :: forall m t a b. (Monad m, Traversable (Base t), Recursive t, Corecursive t)
=> (Base t (Cofree (Base t) b) -> m b)
-> (a -> m (Base t (Free (Base t) a)))
-> a -> m b
chronoM phi psi = (histoM phi :: t -> m b) <=< (futuM psi :: a -> m t)
cochronoM :: (Monad m, Corecursive c, Traversable (Base c), Traversable (Base t), Recursive t)
=> (Base t (Cofree (Base t) a) -> m a)
-> (a -> m (Base c (Free (Base c) a)))
-> t -> m c
cochronoM phi psi = futuM psi <=< histoM phi
dynaM :: (Monad m, Traversable (Base t), Recursive t, Corecursive t)
=> (Base t (Cofree (Base t) b) -> m b)
-> (a -> m (Base t a))
-> a -> m b
dynaM phi psi = chronoM' phi (return . fmap Pure <=< psi)
dynaM' :: forall m t a c. (Monad m, Traversable (Base t), Recursive t, Corecursive t)
=> (Base t (Cofree (Base t) c) -> m c)
-> (a -> m (Base t a))
-> a -> m c
dynaM' phi psi = (histoM phi :: t -> m c) <=< (anaM psi :: a -> m t)
dynaM'' :: (Monad m, Traversable t)
=> (t (Cofree t c) -> m c)
-> (a -> m (t a))
-> a -> m c
dynaM'' phi psi = return . extract <=< hyloM f psi
where f = liftM2 (:<) <$> phi <*> return
codynaM :: (Monad m, Traversable t)
=> (t b -> m b)
-> (a -> m (t (Free t a)))
-> a -> m b
codynaM phi psi = chronoM' (phi . fmap extract) psi
codynaM' :: (Monad m, Corecursive c, Traversable (Base c), Traversable (Base t), Recursive t)
=> (Base t (Cofree (Base t) a) -> m a)
-> (a -> m (Base c a))
-> t -> m c
codynaM' phi psi = anaM psi <=< histoM phi
codynaM'' :: (Monad m, Traversable t)
=> (t b -> m b)
-> (a -> m (t (Free t a)))
-> a -> m b
codynaM'' phi psi = hyloM phi g . Pure
where g (Pure a) = psi a
g (Free fb) = return fb
mutuM :: (Monad m, Traversable (Base t), Recursive t)
=> (Base t (a, b) -> m b)
-> (Base t (a, b) -> m a)
-> t -> m b
mutuM q p = v q p
where u f g = f <=< mapM (liftM2 (,) <$> u f g <*> v g f) . project
v g f = g <=< mapM (liftM2 (,) <$> u f g <*> v g f) . project
mutuM' :: (Monad m, Traversable (Base t), Recursive t)
=> (a -> b)
-> (Base t a -> m a)
-> t -> m b
mutuM' f phi = return . f <=< cataM phi
comutuM :: (Monad m, Traversable (Base t), Corecursive t)
=> (b -> m (Base t (Either a b)))
-> (a -> m (Base t (Either a b)))
-> b -> m t
comutuM q p = v q p
where u f g = fmap embed . mapM (either (u f g) (v g f)) <=< f
v g f = fmap embed . mapM (either (u f g) (v g f)) <=< g
comutuM' :: (Monad m, Traversable (Base t), Corecursive t)
=> (b -> a)
-> (a -> m (Base t a))
-> b -> m t
comutuM' f psi = anaM psi . f
preproM :: (Monad m, Traversable (Base t), Recursive t, Corecursive t)
=> (Base t t -> m (Base t t))
-> (Base t a -> m a)
-> t -> m a
preproM h phi = u
where u = phi <=< mapM f . project
f = u <=< cataM (return . embed <=< h)
postproM :: (Monad m, Traversable (Base t), Recursive t, Corecursive t)
=> (Base t t -> m (Base t t))
-> (a -> m (Base t a))
-> a -> m t
postproM h psi = u
where u = return . embed <=< mapM f <=< psi
f = anaM (h . project) <=< u
cascadeM :: (Monad m, Corecursive (f a), Traversable (Base (f a)), Traversable f, Recursive (f a))
=> (a -> m a)
-> f a -> m (f a)
cascadeM f = u
where u = return . embed <=< mapM u <=< mapM (mapM f) . project
iterateM :: (Monad m, Corecursive (f a), Traversable (Base (f a)), Traversable f, Recursive (f a))
=> (a -> m a)
-> f a -> m (f a)
iterateM f = u
where u = return . embed <=< mapM (mapM f) <=< mapM u . project
gcataM :: (Monad m, Comonad w, Traversable w, Traversable (Base t), Recursive t, b ~ w a)
=> (Base t (w b) -> m (w (Base t b)))
-> (Base t (w a) -> m a)
-> t -> m a
gcataM k g = liftM extract . cataM phi
where phi = mapM g <=< k <=< return . fmap duplicate
gcataM' :: (Monad m, Comonad w, Traversable w, Traversable (Base t), Recursive t, b ~ w a)
=> (Base t (w b) -> m (w (Base t b)))
-> (Base t (w a) -> m a)
-> t -> m a
gcataM' k g = g <=< return . extract <=< c
where c = k <=< mapM u . project
u = return . duplicate <=< mapM g <=< c