{-# LANGUAGE FlexibleContexts #-} {-# LANGUAGE FlexibleInstances #-} {-# LANGUAGE GADTs #-} {-# LANGUAGE Rank2Types #-} {-# LANGUAGE StandaloneDeriving #-} {-# LANGUAGE TypeFamilies #-} {-# LANGUAGE UndecidableInstances #-} {-# LANGUAGE ConstrainedClassMethods #-} {-# LANGUAGE DeriveDataTypeable #-} {-# LANGUAGE DeriveGeneric #-} ----------------------------------------------------------------------------- -- | -- Copyright : (C) 2008-2015 Edward Kmett -- License : BSD-style (see the file LICENSE) -- -- Maintainer : Edward Kmett -- Stability : experimental -- Portability : non-portable -- ---------------------------------------------------------------------------- module Data.Functor.Foldable ( -- * Base functors for fixed points Base , ListF(..) -- * Fixed points , Fix(..), unfix , Mu(..) , Nu(..) -- * Folding , Recursive(..) -- ** Combinators , zygo , mutu -- * Unfolding , Corecursive(..) -- * Refolding , hylo -- ** Changing representation , refix -- * Mendler-style , mcata , mhisto -- * Elgot (co)algebras , 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) -- ^ a (Base t)-algebra -> t -- ^ fixed point -> a -- ^ result 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 -- | Fokkinga's prepromorphism 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 (Base t)-coalgebra -> a -- ^ seed -> t -- ^ resulting fixed point 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 -- | Fokkinga's postpromorphism postpro :: Recursive t => (forall b. Base t b -> Base t b) -- natural transformation -> (a -> Base t a) -- a (Base t)-coalgebra -> a -- seed -> t postpro e g = a where a = embed . fmap (ana (e . project) . a) . g -- | A generalized postpromorphism gpostpro :: (Recursive t, Monad m) => (forall b. m (Base t b) -> Base t (m b)) -- distributive law -> (forall c. Base t c -> Base t c) -- natural transformation -> (a -> Base t (m a)) -- a (Base t)-m-coalgebra -> a -- seed -> 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 -- | Base functor of @[]@. 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 -- These instances cannot be auto-derived on with GHC <= 7.6 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) -- If you are looking for instances for the free alternative and free -- applicative, I'm sorry to disapoint you but you won't find them in this -- package. They can be considered recurive, but using non-uniform recursion; -- this package only implements uniformly recursive folds / unfolds. -- | Example boring stub for non-recursive data types type instance Base (Maybe a) = Const (Maybe a) instance Recursive (Maybe a) where project = Const instance Corecursive (Maybe a) where embed = getConst -- | Example boring stub for non-recursive data types 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 ------------------------------------------------------------------------------- -- Fix ------------------------------------------------------------------------------- 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 ------------------------------------------------------------------------------- -- | Lambek's lemma provides a default definition for 'project' in terms of 'cata' and 'embed' lambek :: (Recursive t, Corecursive t) => (t -> Base t t) lambek = cata (fmap embed) -- | The dual of Lambek's lemma, provides a default definition for 'embed' in terms of 'ana' and 'project' 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 -- | Mendler-style iteration mcata :: (forall y. (y -> c) -> f y -> c) -> Fix f -> c mcata psi = psi (mcata psi) . unfix -- | Mendler-style course-of-value iteration mhisto :: (forall y. (y -> c) -> (y -> f y) -> f y -> c) -> Fix f -> c mhisto psi = psi (mhisto psi) unfix . unfix -- | Elgot algebras elgot :: Functor f => (f a -> a) -> (b -> Either a (f b)) -> b -> a elgot phi psi = h where h = (id ||| phi . fmap h) . psi -- | Elgot coalgebras: coelgot :: Functor f => ((a, f b) -> b) -> (a -> f a) -> a -> b coelgot phi psi = h where h = phi . (id &&& fmap h . psi) ------------------------------------------------------------------------------- -- Not exposed anywhere ------------------------------------------------------------------------------- -- | Read a list (using square brackets and commas), given a function -- for reading elements. _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]