{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE Rank2Types #-}
{-# LANGUAGE StandaloneDeriving #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE UndecidableInstances #-}
{-# LANGUAGE ConstrainedClassMethods #-}
{-# LANGUAGE DeriveDataTypeable #-}
{-# LANGUAGE DeriveGeneric #-}
module Data.Functor.Foldable
(
Base
, ListF(..)
, Fix(..), unfix
, Mu(..)
, Nu(..)
, Recursive(..)
, zygo
, mutu
, Corecursive(..)
, hylo
, refix
, mcata
, mhisto
, elgot
, coelgot
) where
import Control.Applicative
import Control.Arrow
import Control.Monad (join)
import Data.Data
import Data.Function (on)
import Data.Functor.Classes
import Data.List.NonEmpty (NonEmpty ((:|)), nonEmpty, toList)
import Data.Monoid (Monoid (..))
import GHC.Generics (Generic, Generic1)
import Numeric.Natural
import Prelude
import Text.Read
import qualified Data.Foldable as F
import qualified Data.Traversable as T
import qualified Data.Bifoldable as Bi
import qualified Data.Bifunctor as Bi
import qualified Data.Bitraversable as Bi
import Data.Functor.Base
import qualified Data.Functor.Base as NEF (NonEmptyF (..))
type family Base t :: * -> *
class Functor (Base t) => Recursive t where
project :: t -> Base t t
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
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 . cata (embed . e)) . project
class Functor (Base t) => Corecursive t where
embed :: Base t t -> t
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 (ana (e . project) . 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 (ana (e . project) . a . join) . k . fmap g
hylo :: Functor f => (f b -> b) -> (a -> f a) -> a -> b
hylo f g = h where h = f . fmap h . g
data ListF a b = Nil | Cons a b
deriving (Eq,Ord,Show,Read,Typeable
, Generic
, Generic1
)
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
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 (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
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)
deriving instance Typeable Fix
deriving instance (Typeable f, Data (f (Fix f))) => Data (Fix f)
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
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 (cata 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)
instance (Functor f, Read1 f) => Read (Mu f) where
readPrec = parens $ prec 10 $ do
Ident "fromFix" <- lexP
fromFix <$> step readPrec
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)
instance (Functor f, Read1 f) => Read (Nu f) where
readPrec = parens $ prec 10 $ do
Ident "fromFix" <- lexP
fromFix <$> step readPrec
zygo :: Recursive t => (Base t b -> b) -> (Base t (b, a) -> a) -> t -> a
zygo f g = snd . cata (\x -> (f (fmap fst x), g x))
mutu :: (Recursive t) => (Base t (a, a) -> a) -> (Base t (a, a) -> a) -> t -> a
mutu f g = g . fmap (\x -> (mutu g f x, mutu f g x)) . project
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)
_readListWith :: ReadS a -> ReadS [a]
_readListWith rp =
readParen False (\r -> [pr | ("[",s) <- lex r, pr <- readl s])
where
readl s = [([],t) | ("]",t) <- lex s] ++
[(x:xs,u) | (x,t) <- rp s, (xs,u) <- readl' t]
readl' s = [([],t) | ("]",t) <- lex s] ++
[(x:xs,v) | (",",t) <- lex s, (x,u) <- rp t, (xs,v) <- readl' u]