{-# LANGUAGE CPP, TypeFamilies, Rank2Types, FlexibleContexts, FlexibleInstances, GADTs, StandaloneDeriving, UndecidableInstances #-}
#include "recursion-schemes-common.h"
#ifdef __GLASGOW_HASKELL__
{-# LANGUAGE DeriveDataTypeable #-}
#if __GLASGOW_HASKELL__ >= 800
{-# LANGUAGE ConstrainedClassMethods #-}
#endif
#if HAS_GENERIC
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE ScopedTypeVariables, DefaultSignatures, MultiParamTypeClasses, TypeOperators #-}
#endif
#endif
module Data.Functor.Foldable
(
Base
, ListF(..)
, Fix(..), unfix
, Mu(..), hoistMu
, Nu(..), hoistNu
, Recursive(..)
, gapo
, gcata
, zygo
, gzygo
, histo
, ghisto
, futu
, gfutu
, chrono
, gchrono
, distCata
, distPara
, distParaT
, distZygo
, distZygoT
, distHisto
, distGHisto
, distFutu
, distGFutu
, Corecursive(..)
, gana
, distAna
, distApo
, distGApo
, distGApoT
, hylo
, ghylo
, hoist
, refix
, fold, gfold
, unfold, gunfold
, refold, grefold
, mcata
, mhisto
, elgot
, coelgot
, zygoHistoPrepro
, cataA
, transverse
, cotransverse
) where
import Control.Applicative
import Control.Comonad
import Control.Comonad.Trans.Class
import Control.Comonad.Trans.Env
import qualified Control.Comonad.Cofree as Cofree
import Control.Comonad.Cofree (Cofree(..))
import Control.Comonad.Trans.Cofree (CofreeF, CofreeT(..))
import qualified Control.Comonad.Trans.Cofree as CCTC
import Control.Monad (liftM, join)
import Control.Monad.Free (Free(..))
import qualified Control.Monad.Free.Church as CMFC
import Control.Monad.Trans.Except (ExceptT(..), runExceptT)
import Control.Monad.Trans.Free (FreeF, FreeT(..))
import qualified Control.Monad.Trans.Free as CMTF
import Data.Functor.Identity
import Control.Arrow
import Data.Function (on)
import Data.Functor.Classes
import Data.Functor.Compose (Compose(..))
import Data.List.NonEmpty(NonEmpty((:|)), nonEmpty, toList)
import Text.Read
import Text.Show
#ifdef __GLASGOW_HASKELL__
import Data.Data hiding (gunfold)
#if HAS_POLY_TYPEABLE
#else
import qualified Data.Data as Data
#endif
#if HAS_GENERIC
import GHC.Generics (Generic (..), M1 (..), V1, U1, K1 (..), (:+:) (..), (:*:) (..))
#endif
#if HAS_GENERIC1
import GHC.Generics (Generic1)
#endif
#endif
import Numeric.Natural
import Data.Monoid (Monoid (..))
import Prelude
import qualified Data.Foldable as F
import qualified Data.Traversable as T
import qualified Data.Bifunctor as Bi
import qualified Data.Bifoldable as Bi
import qualified Data.Bitraversable as Bi
import Data.Functor.Base hiding (head, tail)
import qualified Data.Functor.Base as NEF (NonEmptyF(..))
type family Base t :: * -> *
class Functor (Base t) => Recursive t where
project :: t -> Base t t
#ifdef HAS_GENERIC
default project :: (Generic t, Generic (Base t t), GCoerce (Rep t) (Rep (Base t t))) => t -> Base t t
project = to . gcoerce . from
#endif
cata :: (Base t a -> a)
-> t
-> a
cata f = c where c = f . fmap c . project
para :: (Base t (t, a) -> a) -> t -> a
para t = p where p x = t . fmap ((,) <*> p) $ project x
gpara :: (Corecursive t, Comonad w) => (forall b. Base t (w b) -> w (Base t b)) -> (Base t (EnvT t w a) -> a) -> t -> a
gpara t = gzygo embed t
prepro
:: Corecursive t
=> (forall b. Base t b -> Base t b)
-> (Base t a -> a)
-> t
-> a
prepro e f = c where c = f . fmap (c . hoist e) . project
gprepro
:: (Corecursive t, Comonad w)
=> (forall b. Base t (w b) -> w (Base t b))
-> (forall c. Base t c -> Base t c)
-> (Base t (w a) -> a)
-> t
-> a
gprepro k e f = extract . c where c = fmap f . k . fmap (duplicate . c . hoist e) . project
distPara :: Corecursive t => Base t (t, a) -> (t, Base t a)
distPara = distZygo embed
distParaT :: (Corecursive t, Comonad w) => (forall b. Base t (w b) -> w (Base t b)) -> Base t (EnvT t w a) -> EnvT t w (Base t a)
distParaT t = distZygoT embed t
class Functor (Base t) => Corecursive t where
embed :: Base t t -> t
#ifdef HAS_GENERIC
default embed :: (Generic t, Generic (Base t t), GCoerce (Rep (Base t t)) (Rep t)) => Base t t -> t
embed = to . gcoerce . from
#endif
ana
:: (a -> Base t a)
-> a
-> t
ana g = a where a = embed . fmap a . g
apo :: (a -> Base t (Either t a)) -> a -> t
apo g = a where a = embed . (fmap (either id a)) . g
postpro
:: Recursive t
=> (forall b. Base t b -> Base t b)
-> (a -> Base t a)
-> a
-> t
postpro e g = a where a = embed . fmap (hoist e . a) . g
gpostpro
:: (Recursive t, Monad m)
=> (forall b. m (Base t b) -> Base t (m b))
-> (forall c. Base t c -> Base t c)
-> (a -> Base t (m a))
-> a
-> t
gpostpro k e g = a . return where a = embed . fmap (hoist e . a . join) . k . liftM g
hylo :: Functor f => (f b -> b) -> (a -> f a) -> a -> b
hylo f g = h where h = f . fmap h . g
fold :: Recursive t => (Base t a -> a) -> t -> a
fold = cata
unfold :: Corecursive t => (a -> Base t a) -> a -> t
unfold = ana
refold :: Functor f => (f b -> b) -> (a -> f a) -> a -> b
refold = hylo
data ListF a b = Nil | Cons a b
deriving (Eq,Ord,Show,Read,Typeable
#if HAS_GENERIC
, Generic
#endif
#if HAS_GENERIC1
, Generic1
#endif
)
#ifdef LIFTED_FUNCTOR_CLASSES
instance Eq2 ListF where
liftEq2 _ _ Nil Nil = True
liftEq2 f g (Cons a b) (Cons a' b') = f a a' && g b b'
liftEq2 _ _ _ _ = False
instance Eq a => Eq1 (ListF a) where
liftEq = liftEq2 (==)
instance Ord2 ListF where
liftCompare2 _ _ Nil Nil = EQ
liftCompare2 _ _ Nil _ = LT
liftCompare2 _ _ _ Nil = GT
liftCompare2 f g (Cons a b) (Cons a' b') = f a a' `mappend` g b b'
instance Ord a => Ord1 (ListF a) where
liftCompare = liftCompare2 compare
instance Show a => Show1 (ListF a) where
liftShowsPrec = liftShowsPrec2 showsPrec showList
instance Show2 ListF where
liftShowsPrec2 _ _ _ _ _ Nil = showString "Nil"
liftShowsPrec2 sa _ sb _ d (Cons a b) = showParen (d > 10)
$ showString "Cons "
. sa 11 a
. showString " "
. sb 11 b
instance Read2 ListF where
liftReadsPrec2 ra _ rb _ d = readParen (d > 10) $ \s -> nil s ++ cons s
where
nil s0 = do
("Nil", s1) <- lex s0
return (Nil, s1)
cons s0 = do
("Cons", s1) <- lex s0
(a, s2) <- ra 11 s1
(b, s3) <- rb 11 s2
return (Cons a b, s3)
instance Read a => Read1 (ListF a) where
liftReadsPrec = liftReadsPrec2 readsPrec readList
#else
instance Eq a => Eq1 (ListF a) where eq1 = (==)
instance Ord a => Ord1 (ListF a) where compare1 = compare
instance Show a => Show1 (ListF a) where showsPrec1 = showsPrec
instance Read a => Read1 (ListF a) where readsPrec1 = readsPrec
#endif
instance Functor (ListF a) where
fmap _ Nil = Nil
fmap f (Cons a b) = Cons a (f b)
instance F.Foldable (ListF a) where
foldMap _ Nil = Data.Monoid.mempty
foldMap f (Cons _ b) = f b
instance T.Traversable (ListF a) where
traverse _ Nil = pure Nil
traverse f (Cons a b) = Cons a <$> f b
instance Bi.Bifunctor ListF where
bimap _ _ Nil = Nil
bimap f g (Cons a b) = Cons (f a) (g b)
instance Bi.Bifoldable ListF where
bifoldMap _ _ Nil = mempty
bifoldMap f g (Cons a b) = mappend (f a) (g b)
instance Bi.Bitraversable ListF where
bitraverse _ _ Nil = pure Nil
bitraverse f g (Cons a b) = Cons <$> f a <*> g b
type instance Base [a] = ListF a
instance Recursive [a] where
project (x:xs) = Cons x xs
project [] = Nil
para f (x:xs) = f (Cons x (xs, para f xs))
para f [] = f Nil
instance Corecursive [a] where
embed (Cons x xs) = x:xs
embed Nil = []
apo f a = case f a of
Cons x (Left xs) -> x : xs
Cons x (Right b) -> x : apo f b
Nil -> []
type instance Base (NonEmpty a) = NonEmptyF a
instance Recursive (NonEmpty a) where
project (x:|xs) = NonEmptyF x $ nonEmpty xs
instance Corecursive (NonEmpty a) where
embed = (:|) <$> NEF.head <*> (maybe [] toList <$> NEF.tail)
type instance Base Natural = Maybe
instance Recursive Natural where
project 0 = Nothing
project n = Just (n - 1)
instance Corecursive Natural where
embed = maybe 0 (+1)
type instance Base (Cofree f a) = CofreeF f a
instance Functor f => Recursive (Cofree f a) where
project (x :< xs) = x CCTC.:< xs
instance Functor f => Corecursive (Cofree f a) where
embed (x CCTC.:< xs) = x :< xs
type instance Base (CofreeT f w a) = Compose w (CofreeF f a)
instance (Functor w, Functor f) => Recursive (CofreeT f w a) where
project = Compose . runCofreeT
instance (Functor w, Functor f) => Corecursive (CofreeT f w a) where
embed = CofreeT . getCompose
type instance Base (Free f a) = FreeF f a
instance Functor f => Recursive (Free f a) where
project (Pure a) = CMTF.Pure a
project (Free f) = CMTF.Free f
improveF :: Functor f => CMFC.F f a -> Free f a
improveF x = CMFC.improve (CMFC.fromF x)
instance Functor f => Corecursive (Free f a) where
embed (CMTF.Pure a) = Pure a
embed (CMTF.Free f) = Free f
ana coalg = improveF . ana coalg
postpro nat coalg = improveF . postpro nat coalg
gpostpro dist nat coalg = improveF . gpostpro dist nat coalg
type instance Base (FreeT f m a) = Compose m (FreeF f a)
instance (Functor m, Functor f) => Recursive (FreeT f m a) where
project = Compose . runFreeT
instance (Functor m, Functor f) => Corecursive (FreeT f m a) where
embed = FreeT . getCompose
type instance Base (Maybe a) = Const (Maybe a)
instance Recursive (Maybe a) where project = Const
instance Corecursive (Maybe a) where embed = getConst
type instance Base (Either a b) = Const (Either a b)
instance Recursive (Either a b) where project = Const
instance Corecursive (Either a b) where embed = getConst
gfold, gcata
:: (Recursive t, Comonad w)
=> (forall b. Base t (w b) -> w (Base t b))
-> (Base t (w a) -> a)
-> t
-> a
gcata k g = g . extract . c where
c = k . fmap (duplicate . fmap g . c) . project
gfold k g t = gcata k g t
distCata :: Functor f => f (Identity a) -> Identity (f a)
distCata = Identity . fmap runIdentity
gunfold, gana
:: (Corecursive t, Monad m)
=> (forall b. m (Base t b) -> Base t (m b))
-> (a -> Base t (m a))
-> a
-> t
gana k f = a . return . f where
a = embed . fmap (a . liftM f . join) . k
gunfold k f t = gana k f t
distAna :: Functor f => Identity (f a) -> f (Identity a)
distAna = fmap Identity . runIdentity
grefold, ghylo
:: (Comonad w, Functor f, Monad m)
=> (forall c. f (w c) -> w (f c))
-> (forall d. m (f d) -> f (m d))
-> (f (w b) -> b)
-> (a -> f (m a))
-> a
-> b
ghylo w m f g = extract . h . return where
h = fmap f . w . fmap (duplicate . h . join) . m . liftM g
grefold w m f g a = ghylo w m f g a
futu :: Corecursive t => (a -> Base t (Free (Base t) a)) -> a -> t
futu = gana distFutu
gfutu :: (Corecursive t, Functor m, Monad m) => (forall b. m (Base t b) -> Base t (m b)) -> (a -> Base t (FreeT (Base t) m a)) -> a -> t
gfutu g = gana (distGFutu g)
distFutu :: Functor f => Free f (f a) -> f (Free f a)
distFutu (Pure fx) = Pure <$> fx
distFutu (Free ff) = Free . distFutu <$> ff
distGFutu :: (Functor f, Functor h) => (forall b. h (f b) -> f (h b)) -> FreeT f h (f a) -> f (FreeT f h a)
distGFutu k = d where
d = fmap FreeT . k . fmap d' . runFreeT
d' (CMTF.Pure ff) = CMTF.Pure <$> ff
d' (CMTF.Free ff) = CMTF.Free . d <$> ff
newtype Fix f = Fix (f (Fix f))
unfix :: Fix f -> f (Fix f)
unfix (Fix f) = f
instance Eq1 f => Eq (Fix f) where
Fix a == Fix b = eq1 a b
instance Ord1 f => Ord (Fix f) where
compare (Fix a) (Fix b) = compare1 a b
instance Show1 f => Show (Fix f) where
showsPrec d (Fix a) =
showParen (d >= 11)
$ showString "Fix "
. showsPrec1 11 a
instance Read1 f => Read (Fix f) where
readPrec = parens $ prec 10 $ do
Ident "Fix" <- lexP
Fix <$> step (readS_to_Prec readsPrec1)
#ifdef __GLASGOW_HASKELL__
#if HAS_POLY_TYPEABLE
deriving instance Typeable Fix
deriving instance (Typeable f, Data (f (Fix f))) => Data (Fix f)
#else
instance Typeable1 f => Typeable (Fix f) where
typeOf t = mkTyConApp fixTyCon [typeOf1 (undefined `asArgsTypeOf` t)]
where asArgsTypeOf :: f a -> Fix f -> f a
asArgsTypeOf = const
fixTyCon :: TyCon
#if MIN_VERSION_base(4,4,0)
fixTyCon = mkTyCon3 "recursion-schemes" "Data.Functor.Foldable" "Fix"
#else
fixTyCon = mkTyCon "Data.Functor.Foldable.Fix"
#endif
{-# NOINLINE fixTyCon #-}
instance (Typeable1 f, Data (f (Fix f))) => Data (Fix f) where
gfoldl f z (Fix a) = z Fix `f` a
toConstr _ = fixConstr
gunfold k z c = case constrIndex c of
1 -> k (z (Fix))
_ -> error "gunfold"
dataTypeOf _ = fixDataType
fixConstr :: Constr
fixConstr = mkConstr fixDataType "Fix" [] Prefix
fixDataType :: DataType
fixDataType = mkDataType "Data.Functor.Foldable.Fix" [fixConstr]
#endif
#endif
type instance Base (Fix f) = f
instance Functor f => Recursive (Fix f) where
project (Fix a) = a
instance Functor f => Corecursive (Fix f) where
embed = Fix
hoist :: (Recursive s, Corecursive t)
=> (forall a. Base s a -> Base t a) -> s -> t
hoist n = cata (embed . n)
refix :: (Recursive s, Corecursive t, Base s ~ Base t) => s -> t
refix = cata embed
toFix :: Recursive t => t -> Fix (Base t)
toFix = refix
fromFix :: Corecursive t => Fix (Base t) -> t
fromFix = refix
lambek :: (Recursive t, Corecursive t) => (t -> Base t t)
lambek = cata (fmap embed)
colambek :: (Recursive t, Corecursive t) => (Base t t -> t)
colambek = ana (fmap project)
newtype Mu f = Mu (forall a. (f a -> a) -> a)
type instance Base (Mu f) = f
instance Functor f => Recursive (Mu f) where
project = lambek
cata f (Mu g) = g f
instance Functor f => Corecursive (Mu f) where
embed m = Mu (\f -> f (fmap (fold f) m))
instance (Functor f, Eq1 f) => Eq (Mu f) where
(==) = (==) `on` toFix
instance (Functor f, Ord1 f) => Ord (Mu f) where
compare = compare `on` toFix
instance (Functor f, Show1 f) => Show (Mu f) where
showsPrec d f = showParen (d > 10) $
showString "fromFix " . showsPrec 11 (toFix f)
#ifdef __GLASGOW_HASKELL__
instance (Functor f, Read1 f) => Read (Mu f) where
readPrec = parens $ prec 10 $ do
Ident "fromFix" <- lexP
fromFix <$> step readPrec
#endif
hoistMu :: (forall a. f a -> g a) -> Mu f -> Mu g
hoistMu n (Mu mk) = Mu $ \roll -> mk (roll . n)
type instance Base (CMFC.F f a) = FreeF f a
cmfcCata :: (a -> r) -> (f r -> r) -> CMFC.F f a -> r
cmfcCata p f (CMFC.F run) = run p f
instance Functor f => Recursive (CMFC.F f a) where
project = lambek
cata f = cmfcCata (f . CMTF.Pure) (f . CMTF.Free)
instance Functor f => Corecursive (CMFC.F f a) where
embed (CMTF.Pure a) = CMFC.F $ \p _ -> p a
embed (CMTF.Free fr) = CMFC.F $ \p f -> f $ fmap (cmfcCata p f) fr
data Nu f where Nu :: (a -> f a) -> a -> Nu f
type instance Base (Nu f) = f
instance Functor f => Corecursive (Nu f) where
embed = colambek
ana = Nu
instance Functor f => Recursive (Nu f) where
project (Nu f a) = Nu f <$> f a
instance (Functor f, Eq1 f) => Eq (Nu f) where
(==) = (==) `on` toFix
instance (Functor f, Ord1 f) => Ord (Nu f) where
compare = compare `on` toFix
instance (Functor f, Show1 f) => Show (Nu f) where
showsPrec d f = showParen (d > 10) $
showString "fromFix " . showsPrec 11 (toFix f)
#ifdef __GLASGOW_HASKELL__
instance (Functor f, Read1 f) => Read (Nu f) where
readPrec = parens $ prec 10 $ do
Ident "fromFix" <- lexP
fromFix <$> step readPrec
#endif
hoistNu :: (forall a. f a -> g a) -> Nu f -> Nu g
hoistNu n (Nu next seed) = Nu (n . next) seed
zygo :: Recursive t => (Base t b -> b) -> (Base t (b, a) -> a) -> t -> a
zygo f = gfold (distZygo f)
distZygo
:: Functor f
=> (f b -> b)
-> (f (b, a) -> (b, f a))
distZygo g m = (g (fmap fst m), fmap snd m)
gzygo
:: (Recursive t, Comonad w)
=> (Base t b -> b)
-> (forall c. Base t (w c) -> w (Base t c))
-> (Base t (EnvT b w a) -> a)
-> t
-> a
gzygo f w = gfold (distZygoT f w)
distZygoT
:: (Functor f, Comonad w)
=> (f b -> b)
-> (forall c. f (w c) -> w (f c))
-> f (EnvT b w a) -> EnvT b w (f a)
distZygoT g k fe = EnvT (g (getEnv <$> fe)) (k (lower <$> fe))
where getEnv (EnvT e _) = e
gapo :: Corecursive t => (b -> Base t b) -> (a -> Base t (Either b a)) -> a -> t
gapo g = gunfold (distGApo g)
distApo :: Recursive t => Either t (Base t a) -> Base t (Either t a)
distApo = distGApo project
distGApo :: Functor f => (b -> f b) -> Either b (f a) -> f (Either b a)
distGApo f = either (fmap Left . f) (fmap Right)
distGApoT
:: (Functor f, Functor m)
=> (b -> f b)
-> (forall c. m (f c) -> f (m c))
-> ExceptT b m (f a)
-> f (ExceptT b m a)
distGApoT g k = fmap ExceptT . k . fmap (distGApo g) . runExceptT
histo :: Recursive t => (Base t (Cofree (Base t) a) -> a) -> t -> a
histo = gcata distHisto
ghisto :: (Recursive t, Comonad w) => (forall b. Base t (w b) -> w (Base t b)) -> (Base t (CofreeT (Base t) w a) -> a) -> t -> a
ghisto g = gcata (distGHisto g)
distHisto :: Functor f => f (Cofree f a) -> Cofree f (f a)
distHisto fc = fmap extract fc :< fmap (distHisto . Cofree.unwrap) fc
distGHisto :: (Functor f, Functor h) => (forall b. f (h b) -> h (f b)) -> f (CofreeT f h a) -> CofreeT f h (f a)
distGHisto k = d where d = CofreeT . fmap (\fc -> fmap CCTC.headF fc CCTC.:< fmap (d . CCTC.tailF) fc) . k . fmap runCofreeT
chrono :: Functor f => (f (Cofree f b) -> b) -> (a -> f (Free f a)) -> (a -> b)
chrono = ghylo distHisto distFutu
gchrono :: (Functor f, Functor w, Functor m, Comonad w, Monad m) =>
(forall c. f (w c) -> w (f c)) ->
(forall c. m (f c) -> f (m c)) ->
(f (CofreeT f w b) -> b) -> (a -> f (FreeT f m a)) ->
(a -> b)
gchrono w m = ghylo (distGHisto w) (distGFutu m)
mcata :: (forall y. (y -> c) -> f y -> c) -> Fix f -> c
mcata psi = psi (mcata psi) . unfix
mhisto :: (forall y. (y -> c) -> (y -> f y) -> f y -> c) -> Fix f -> c
mhisto psi = psi (mhisto psi) unfix . unfix
elgot :: Functor f => (f a -> a) -> (b -> Either a (f b)) -> b -> a
elgot phi psi = h where h = (id ||| phi . fmap h) . psi
coelgot :: Functor f => ((a, f b) -> b) -> (a -> f a) -> a -> b
coelgot phi psi = h where h = phi . (id &&& fmap h . psi)
zygoHistoPrepro
:: (Corecursive t, Recursive t)
=> (Base t b -> b)
-> (forall c. Base t c -> Base t c)
-> (Base t (EnvT b (Cofree (Base t)) a) -> a)
-> t
-> a
zygoHistoPrepro f g t = gprepro (distZygoT f distHisto) g t
cataA :: (Recursive t) => (Base t (f a) -> f a) -> t -> f a
cataA = cata
transverse :: (Recursive s, Corecursive t, Functor f)
=> (forall a. Base s (f a) -> f (Base t a)) -> s -> f t
transverse n = cata (fmap embed . n)
cotransverse :: (Recursive s, Corecursive t, Functor f)
=> (forall a. f (Base s a) -> Base t (f a)) -> f s -> t
cotransverse n = ana (n . fmap project)
class GCoerce f g where
gcoerce :: f a -> g a
instance GCoerce f g => GCoerce (M1 i c f) (M1 i c' g) where
gcoerce (M1 x) = M1 (gcoerce x)
instance GCoerce (K1 i c) (K1 j c) where
gcoerce = K1 . unK1
instance GCoerce U1 U1 where
gcoerce = id
instance GCoerce V1 V1 where
gcoerce = id
instance (GCoerce f g, GCoerce f' g') => GCoerce (f :*: f') (g :*: g') where
gcoerce (x :*: y) = gcoerce x :*: gcoerce y
instance (GCoerce f g, GCoerce f' g') => GCoerce (f :+: f') (g :+: g') where
gcoerce (L1 x) = L1 (gcoerce x)
gcoerce (R1 x) = R1 (gcoerce x)