{-# LANGUAGE DataKinds #-} {-# LANGUAGE DeriveDataTypeable #-} {-# LANGUAGE DeriveGeneric #-} {-# LANGUAGE LambdaCase #-} {-# LANGUAGE PolyKinds #-} {-# LANGUAGE RankNTypes #-} {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE TypeOperators #-} {-# LANGUAGE UndecidableInstances #-} {-# OPTIONS_GHC -Wall -Wno-name-shadowing #-} module Data.IFunctor.Foldable ( -- * Fixpoint for indexed types IFix (..) -- * Morphisms -- * Constructive morphisms , cata , prepro , para , zygo , histo -- * Destructive morphisms , ana , postpro , apo , gapo , futu -- * Combined morphisms , hylo , dyna , chrono , meta , elgot , coelgot -- * Monadic morphisms , cataM , paraM , anaM , apoM , hyloM , dynaM -- * Distribution Laws , DistLaw -- * Constructive distribution laws , distCata , distPara , distZygo , distHisto -- * Destructive distribution laws , distAna , distApo , distGApo , distFutu -- * Generalized morphisms , gfold , gunfold , ghylo , gprepro , gpostpro -- * Generalized monadic morphisms , gfoldM , gunfoldM , ghyloM -- * Re-exports , module Data.Functor.Const , module Data.Functor.Product , module Data.Functor.Sum , module Data.IComonad , module Data.IFunction , module Data.IFunctor , module Data.IFunctor.Classes , module Data.IFunctor.ICofree , module Data.IFunctor.IFree , module Data.IFunctor.IIdentity , module Data.IMonad , module Data.ITraversable , module Singlethongs ) where import Control.Monad ((<=<)) import Data.Functor.Const (Const (..)) import Data.Functor.Product (Product (..)) import Data.Functor.Sum (Sum (..)) import Data.IComonad (IComonad (..)) import Data.IFunction (type (~~>)) import Data.IFunctor (IFunctor (..)) import Data.IFunctor.Classes import Data.IFunctor.ICofree (ICofree (..)) import Data.IFunctor.IFree (IFree (..)) import Data.IFunctor.IIdentity (IIdentity (..)) import Data.IMonad (IMonad (..)) import Data.ITraversable (ITraversable (..), imapDefault) import Data.Typeable (Typeable) import GHC.Generics (Generic, Generic1) import Singlethongs (SingI (sing)) import Text.Read -- | Fixpoint type newtype IFix f ix = IFix { unIFix :: f (IFix f) ix } deriving (Typeable, Generic, Generic1) instance (IShow f, SingI ix) => Show (IFix f ix) where showsPrec p (IFix x) = showParen (p > 10) $ showString "IFix " . ishowsPrec showsPrec 11 x instance (IRead f, SingI ix) => Read (IFix f ix) where readPrec = parens $ prec 10 $ do Ident "IFix" <- lexP x <- step $ ireadPrec readPrec pure $ IFix x instance (IEq f, SingI ix) => Eq (IFix f ix) where IFix x == IFix y = ieq (==) x y instance (IOrd f, SingI ix) => Ord (IFix f ix) where IFix x `compare` IFix y = icompare compare x y -- * Morphisms -- | Catamorphism, ie. fold cata :: IFunctor f => (f a ~~> a) -> (IFix f ~~> a) cata f = gfold distCata (f . imap runIIdentity) -- | Fokkinga's prepromorphism prepro :: IFunctor f => (forall b. f b ~~> f b) -> (f a ~~> a) -> (IFix f ~~> a) prepro e f = gprepro distCata e (f . imap runIIdentity) -- | Paramorphism para :: IFunctor f => (f (Product (IFix f) a) ~~> a) -> (IFix f ~~> a) para = gfold distPara -- | Zygomorphism zygo :: IFunctor f => (f b ~~> b) -> (f (Product b a) ~~> a) -> (IFix f ~~> a) zygo f = gfold (distZygo f) -- | Histomorphism histo :: IFunctor f => (f (ICofree f a) ~~> a) -> (IFix f ~~> a) histo = gfold distHisto -- | Anamorphism, ie. unfold ana :: IFunctor f => (a ~~> f a) -> (a ~~> IFix f) ana g = gunfold distAna (imap IIdentity . g) -- | Fokkinga's postpromorphism postpro :: IFunctor f => (forall b. f b ~~> f b) -> (a ~~> f a) -> (a ~~> IFix f) postpro e g = gpostpro distAna e (imap IIdentity . g) -- | Apomorphism apo :: IFunctor f => (a ~~> f (Sum (IFix f) a)) -> (a ~~> IFix f) apo = gunfold distApo -- | GApomorphism gapo :: IFunctor f => (b ~~> f b) -> (a ~~> f (Sum b a)) -> (a ~~> IFix f) gapo f = gunfold (distGApo f) -- | Futumorphism futu :: IFunctor f => (a ~~> f (IFree f a)) -> (a ~~> IFix f) futu = gunfold distFutu -- | Hylomorphism, fold then unfold hylo :: IFunctor f => (f b ~~> b) -> (a ~~> f a) -> (a ~~> b) hylo f g = ghylo distCata distAna (f . imap runIIdentity) (imap IIdentity . g) -- | Dynamorphism dyna :: IFunctor f => (f (ICofree f b) ~~> b) -> (a ~~> f a) -> (a ~~> b) dyna f g = ghylo distHisto distAna f (imap IIdentity . g) -- | Chronomorphism chrono :: IFunctor f => (f (ICofree f b) ~~> b) -> (a ~~> f (IFree f a)) -> (a ~~> b) chrono = ghylo distHisto distFutu -- | Metamorphism -- TODO: ensure only 1 pass over structure meta :: (IFunctor f, IFunctor g) => (f a ~~> a) -> (a ~~> b) -> (b ~~> g b) -> (IFix f ~~> IFix g) meta f e g = ana g . e . cata f -- * Elgot algebras elgot :: forall f a b. IFunctor f => (f a ~~> a) -> (b ~~> Sum a (f b)) -> (b ~~> a) elgot phi psi = h where h :: b ~~> a h = (id `sum` (phi . imap h)) . psi sum :: forall a b c. (a ~~> c) -> (b ~~> c) -> (Sum a b ~~> c) sum f _ (InL x) = f x sum _ g (InR x) = g x coelgot :: forall f a b. IFunctor f => (Product a (f b) ~~> b) -> (a ~~> f a) -> (a ~~> b) coelgot phi psi = h where h :: a ~~> b h = phi . (id `product` (imap h . psi)) product :: forall a b c. (a ~~> b) -> (a ~~> c) -> (a ~~> Product b c) product f g x = Pair (f x) (g x) -- * Monadic morphisms -- | Monadic catamorphism cataM :: (ITraversable f, Monad m) => (forall ix. SingI ix => f a ix -> m (a ix)) -> (forall ix. SingI ix => IFix f ix -> m (a ix)) cataM f = gfoldM distCata (f . imap runIIdentity) -- | Monadic Paramorphism paraM :: (ITraversable f, Monad m) => (forall ix. SingI ix => f (Product (IFix f) a) ix -> m (a ix)) -> (forall ix. SingI ix => IFix f ix -> m (a ix)) paraM = gfoldM distPara -- | Monadic anamorphism anaM :: (ITraversable f, Monad m) => (forall ix. SingI ix => a ix -> m (f a ix)) -> (forall ix. SingI ix => a ix -> m (IFix f ix)) anaM g = gunfoldM distAna (fmap (imap IIdentity) . g) -- | Monadic apomorphism apoM :: (ITraversable f, Monad m) => (forall ix. SingI ix => a ix -> m (f (Sum (IFix f) a) ix)) -> (forall ix. SingI ix => a ix -> m (IFix f ix)) apoM = gunfoldM distApo -- | Monadic hylomorphism hyloM :: (ITraversable f, Monad m) => (forall ix. SingI ix => f b ix -> m (b ix)) -> (forall ix. SingI ix => a ix -> m (f a ix)) -> (forall ix. SingI ix => a ix -> m (b ix)) hyloM f g = ghyloM distCata distAna (f . imap runIIdentity) (fmap (imap IIdentity) . g) -- | Monadic dynamorphism dynaM :: (ITraversable f, Monad m) => (forall ix. SingI ix => f (ICofree f b) ix -> m (b ix)) -> (forall ix. SingI ix => a ix -> m (f a ix)) -> (forall ix. SingI ix => a ix -> m (b ix)) dynaM f g = ghyloM distHisto distAna f (fmap (imap IIdentity) . g) -- * Distribution laws -- | Type of distribution laws -- A Constructive morphism means the second part is a 'IComonad' -- A Destructive morphism means the first part is an 'IMonad' type DistLaw f g = forall a. f (g a) ~~> g (f a) -- * Constructive distribution laws distCata :: IFunctor f => DistLaw f IIdentity distCata = IIdentity . imap runIIdentity distPara :: IFunctor f => DistLaw f (Product (IFix f)) distPara = distZygo IFix distZygo :: IFunctor f => (f b ~~> b) -> DistLaw f (Product b) distZygo g m = Pair (g (imap (\(Pair a _) -> a) m)) (imap (\(Pair _ b) -> b) m) distHisto :: IFunctor f => DistLaw f (ICofree f) distHisto x = imap (\(a ::< _) -> a) x ::< imap (\(_ ::< x) -> distHisto x) x -- * Destructive distribution laws distAna :: IFunctor f => DistLaw IIdentity f distAna = imap IIdentity . runIIdentity distApo :: IFunctor f => DistLaw (Sum (IFix f)) f distApo = distGApo unIFix distGApo :: IFunctor f => (b ~~> f b) -> DistLaw (Sum b) f distGApo f (InL x) = imap InL $ f x distGApo _ (InR x) = imap InR x distFutu :: IFunctor f => DistLaw (IFree f) f distFutu (IPure x) = imap IPure x distFutu (IFree x) = imap (IFree . distFutu) x -- * Generalized combinators -- | Generalized fold gfold :: forall f w a. (IFunctor f, IComonad w) => DistLaw f w -> (f (w a) ~~> a) -> (IFix f ~~> a) gfold k g = g . iextract . c where c :: IFix f ~~> w (f (w a)) c = k . imap (iduplicate . imap g . c) . unIFix -- | Generalized unfold gunfold :: forall f m a. (IFunctor f, IMonad m) => DistLaw m f -> (a ~~> f (m a)) -> (a ~~> IFix f) gunfold k f = a . ipure . f where a :: m (f (m a)) ~~> IFix f a = IFix . imap (a . imap f . ijoin) . k -- | Generalized hylomorphism ghylo :: forall f w m a b. (IFunctor f, IComonad w, IMonad m) => DistLaw f w -> DistLaw m f -> f (w b) ~~> b -> a ~~> f (m a) -> a ~~> b ghylo w m f g = iextract . h . ipure where h :: m a ~~> w b h = imap f . w . imap (iduplicate . h . ijoin) . m . imap g -- | Generalized monadic fold gfoldM :: forall f w m a. (ITraversable f, ITraversable w, IComonad w, Monad m) => DistLaw f w -> (forall ix. SingI ix => f (w a) ix -> m (a ix)) -> (forall ix. SingI ix => IFix f ix -> m (a ix)) gfoldM k g = g . iextract <=< c where c :: forall ix. SingI ix => IFix f ix -> m (w (f (w a)) ix) c = fmap k . itraverse (fmap iduplicate . itraverse g <=< c) . unIFix -- | Generalized monadic unfold gunfoldM :: forall f m a x. (ITraversable f, ITraversable m, IMonad m, Monad x) => DistLaw m f -> (forall ix. SingI ix => a ix -> x (f (m a) ix)) -> (forall ix. SingI ix => a ix -> x (IFix f ix)) gunfoldM k f = a . ipure <=< f where a :: SingI ix => m (f (m a)) ix -> x (IFix f ix) a = fmap IFix . itraverse (a <=< itraverse f . ijoin) . k -- | Generalized monadic hylomorphism ghyloM :: forall f w m a b x. (ITraversable f, ITraversable w, ITraversable m, IComonad w, IMonad m, Monad x) => DistLaw f w -> DistLaw m f -> (forall ix. SingI ix => f (w b) ix -> x (b ix)) -> (forall ix. SingI ix => a ix -> x (f (m a) ix)) -> (forall ix. SingI ix => a ix -> x (b ix)) ghyloM w m f g = fmap iextract . h . ipure where h :: SingI ix => m a ix -> x (w b ix) h = itraverse f <=< fmap w . itraverse (fmap iduplicate . h . ijoin) . m <=< itraverse g -- | Generalized prepromorphism gprepro :: forall f w a. (IFunctor f, IComonad w) => DistLaw f w -> (forall c. f c ~~> f c) -> (f (w a) ~~> a) -> (IFix f ~~> a) gprepro k e f = iextract . c where c :: IFix f ~~> w a c = imap f . k . imap (iduplicate . c . cata (IFix . e)) . unIFix -- | Generalized postpromorphism gpostpro :: forall f m a. (IFunctor f, IMonad m) => DistLaw m f -> (forall c. f c ~~> f c) -> (a ~~> f (m a)) -> (a ~~> IFix f) gpostpro k e g = a . ipure where a :: m a ~~> IFix f a = IFix . imap (cata (IFix . e) . a . ijoin) . k . imap g