{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE KindSignatures #-}
{-# LANGUAGE LiberalTypeSynonyms #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE TypeFamilies #-}
module Generics.MultiRec.Fold where
import Generics.MultiRec.Base
import Generics.MultiRec.HFunctor
import Control.Monad hiding (foldM)
type Algebra' phi f r = forall ix. phi ix -> f r ix -> r ix
type Algebra phi r = Algebra' phi (PF phi) r
type AlgebraF' phi f g r = forall ix. phi ix -> f r ix -> g (r ix)
type AlgebraF phi g r = AlgebraF' phi (PF phi) g r
fold :: (Fam phi, HFunctor phi (PF phi)) =>
Algebra phi r -> phi ix -> ix -> r ix
fold f p = f p . hmap (\ p (I0 x) -> fold f p x) p . from p
foldM :: (Fam phi, HFunctor phi (PF phi), Monad m) =>
AlgebraF phi m r -> phi ix -> ix -> m (r ix)
foldM f p x = hmapM (\ p (I0 x) -> foldM f p x) p (from p x) >>= f p
type CoAlgebra' phi f r = forall ix. phi ix -> r ix -> f r ix
type CoAlgebra phi r = CoAlgebra' phi (PF phi) r
type CoAlgebraF' phi f g r = forall ix. phi ix -> r ix -> g (f r ix)
type CoAlgebraF phi g r = CoAlgebraF' phi (PF phi) g r
unfold :: (Fam phi, HFunctor phi (PF phi)) =>
CoAlgebra phi r -> phi ix -> r ix -> ix
unfold f p = to p . hmap (\ p x -> I0 (unfold f p x)) p . f p
unfoldM :: (Fam phi, HFunctor phi (PF phi), Monad m) =>
CoAlgebraF phi m r -> phi ix -> r ix -> m ix
unfoldM f p x = f p x >>= liftM (to p) . hmapM (\ p x -> liftM I0 (unfoldM f p x)) p
type ParaAlgebra' phi f r = forall ix. phi ix -> f r ix -> ix -> r ix
type ParaAlgebra phi r = ParaAlgebra' phi (PF phi) r
type ParaAlgebraF' phi f g r = forall ix. phi ix -> f r ix -> ix -> g (r ix)
type ParaAlgebraF phi g r = ParaAlgebraF' phi (PF phi) g r
para :: (Fam phi, HFunctor phi (PF phi)) =>
ParaAlgebra phi r -> phi ix -> ix -> r ix
para f p x = f p (hmap (\ p (I0 x) -> para f p x) p (from p x)) x
paraM :: (Fam phi, HFunctor phi (PF phi), Monad m) =>
ParaAlgebraF phi m r -> phi ix -> ix -> m (r ix)
paraM f p x = hmapM (\ p (I0 x) -> paraM f p x) p (from p x) >>= \ r -> f p r x
infixr 5 &
infixr :->
type AlgPart f r ix = f r ix -> r ix
type (f :-> g) (r :: * -> *) ix = f r ix -> g r ix
(&) :: (AlgPart a :-> AlgPart b :-> AlgPart (a :+: b)) r ix
(f & g) (L x) = f x
(f & g) (R x) = g x
tag :: AlgPart a r ix -> AlgPart (a :>: ix) r ix'
tag f (Tag x) = f x
con :: AlgPart a r ix -> AlgPart (C c a) r ix
con f (C x) = f x