{-# LANGUAGE CPP #-}
{-# LANGUAGE Rank2Types #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE UndecidableInstances #-}
{-# LANGUAGE MultiParamTypeClasses #-}
#if __GLASGOW_HASKELL__ >= 707
{-# LANGUAGE DeriveDataTypeable #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE StandaloneDeriving #-}
#endif
#include "free-common.h"
module Control.Comonad.Cofree
( Cofree(..)
, ComonadCofree(..)
, section
, coiter
, coiterW
, unfold
, unfoldM
, hoistCofree
, _extract
, _unwrap
, telescoped
, telescoped_
, shoots
, leaves
) where
import Control.Applicative
import Control.Comonad
import Control.Comonad.Trans.Class
import Control.Comonad.Cofree.Class
import Control.Comonad.Env.Class
import Control.Comonad.Store.Class as Class
import Control.Comonad.Traced.Class
import Control.Comonad.Hoist.Class
import Control.Category
import Control.Monad(ap, (>=>), liftM)
import Control.Monad.Zip
import Data.Functor.Bind
import Data.Functor.Classes.Compat
import Data.Functor.Extend
import Data.Data
import Data.Distributive
import Data.Foldable
import Data.Semigroup
import Data.Traversable
import Data.Semigroup.Foldable
import Data.Semigroup.Traversable
import Prelude hiding (id,(.))
#if __GLASGOW_HASKELL__ >= 707
import GHC.Generics hiding (Infix, Prefix)
#endif
infixr 5 :<
data Cofree f a = a :< f (Cofree f a)
#if __GLASGOW_HASKELL__ >= 707
deriving (Typeable, Generic, Generic1)
deriving instance (Typeable f, Data (f (Cofree f a)), Data a) => Data (Cofree f a)
#endif
coiter :: Functor f => (a -> f a) -> a -> Cofree f a
coiter psi a = a :< (coiter psi <$> psi a)
coiterW :: (Comonad w, Functor f) => (w a -> f (w a)) -> w a -> Cofree f a
coiterW psi a = extract a :< (coiterW psi <$> psi a)
unfold :: Functor f => (b -> (a, f b)) -> b -> Cofree f a
unfold f c = case f c of
(x, d) -> x :< fmap (unfold f) d
unfoldM :: (Traversable f, Monad m) => (b -> m (a, f b)) -> b -> m (Cofree f a)
unfoldM f = f >=> \ (x, t) -> (x :<) `liftM` Data.Traversable.mapM (unfoldM f) t
hoistCofree :: Functor f => (forall x . f x -> g x) -> Cofree f a -> Cofree g a
hoistCofree f (x :< y) = x :< f (hoistCofree f <$> y)
instance Functor f => ComonadCofree f (Cofree f) where
unwrap (_ :< as) = as
{-# INLINE unwrap #-}
instance Distributive f => Distributive (Cofree f) where
distribute w = fmap extract w :< fmap distribute (collect unwrap w)
instance Functor f => Functor (Cofree f) where
fmap f (a :< as) = f a :< fmap (fmap f) as
b <$ (_ :< as) = b :< fmap (b <$) as
instance Functor f => Extend (Cofree f) where
extended = extend
{-# INLINE extended #-}
duplicated = duplicate
{-# INLINE duplicated #-}
instance Functor f => Comonad (Cofree f) where
extend f w = f w :< fmap (extend f) (unwrap w)
duplicate w = w :< fmap duplicate (unwrap w)
extract (a :< _) = a
{-# INLINE extract #-}
instance ComonadTrans Cofree where
lower (_ :< as) = fmap extract as
{-# INLINE lower #-}
instance Alternative f => Monad (Cofree f) where
return = pure
{-# INLINE return #-}
(a :< m) >>= k = case k a of
b :< n -> b :< (n <|> fmap (>>= k) m)
instance (Alternative f, MonadZip f) => MonadZip (Cofree f) where
mzip (a :< as) (b :< bs) = (a, b) :< fmap (uncurry mzip) (mzip as bs)
section :: Comonad f => f a -> Cofree f a
section as = extract as :< extend section as
instance Apply f => Apply (Cofree f) where
(f :< fs) <.> (a :< as) = f a :< ((<.>) <$> fs <.> as)
{-# INLINE (<.>) #-}
(f :< fs) <. (_ :< as) = f :< ((<. ) <$> fs <.> as)
{-# INLINE (<.) #-}
(_ :< fs) .> (a :< as) = a :< (( .>) <$> fs <.> as)
{-# INLINE (.>) #-}
instance ComonadApply f => ComonadApply (Cofree f) where
(f :< fs) <@> (a :< as) = f a :< ((<@>) <$> fs <@> as)
{-# INLINE (<@>) #-}
(f :< fs) <@ (_ :< as) = f :< ((<@ ) <$> fs <@> as)
{-# INLINE (<@) #-}
(_ :< fs) @> (a :< as) = a :< (( @>) <$> fs <@> as)
{-# INLINE (@>) #-}
instance Alternative f => Applicative (Cofree f) where
pure x = x :< empty
{-# INLINE pure #-}
(<*>) = ap
{-# INLINE (<*>) #-}
#ifdef LIFTED_FUNCTOR_CLASSES
instance (Show1 f) => Show1 (Cofree f) where
liftShowsPrec sp sl = go
where
goList = liftShowList sp sl
go d (a :< as) = showParen (d > 5) $
sp 6 a . showString " :< " . liftShowsPrec go goList 5 as
#else
instance (Functor f, Show1 f) => Show1 (Cofree f) where
showsPrec1 d (a :< as) = showParen (d > 5) $
showsPrec 6 a . showString " :< " . showsPrec1 5 (fmap Lift1 as)
#endif
#ifdef LIFTED_FUNCTOR_CLASSES
instance (Show1 f, Show a) => Show (Cofree f a) where
#else
instance (Functor f, Show1 f, Show a) => Show (Cofree f a) where
#endif
showsPrec = showsPrec1
#ifdef LIFTED_FUNCTOR_CLASSES
instance (Read1 f) => Read1 (Cofree f) where
liftReadsPrec rp rl = go
where
goList = liftReadList rp rl
go d r = readParen (d > 5)
(\r' -> [(u :< v, w) |
(u, s) <- rp 6 r',
(":<", t) <- lex s,
(v, w) <- liftReadsPrec go goList 5 t]) r
#else
instance (Functor f, Read1 f) => Read1 (Cofree f) where
readsPrec1 d r = readParen (d > 5)
(\r' -> [(u :< fmap lower1 v,w) |
(u, s) <- readsPrec 6 r',
(":<", t) <- lex s,
(v, w) <- readsPrec1 5 t]) r
#endif
#ifdef LIFTED_FUNCTOR_CLASSES
instance (Read1 f, Read a) => Read (Cofree f a) where
#else
instance (Functor f, Read1 f, Read a) => Read (Cofree f a) where
#endif
readsPrec = readsPrec1
#ifdef LIFTED_FUNCTOR_CLASSES
instance (Eq1 f, Eq a) => Eq (Cofree f a) where
#else
instance (Functor f, Eq1 f, Eq a) => Eq (Cofree f a) where
#endif
(==) = eq1
#ifdef LIFTED_FUNCTOR_CLASSES
instance (Eq1 f) => Eq1 (Cofree f) where
liftEq eq = go
where
go (a :< as) (b :< bs) = eq a b && liftEq go as bs
#else
instance (Functor f, Eq1 f) => Eq1 (Cofree f) where
#ifndef HLINT
eq1 (a :< as) (b :< bs) = a == b && eq1 (fmap Lift1 as) (fmap Lift1 bs)
#endif
#endif
#ifdef LIFTED_FUNCTOR_CLASSES
instance (Ord1 f, Ord a) => Ord (Cofree f a) where
#else
instance (Functor f, Ord1 f, Ord a) => Ord (Cofree f a) where
#endif
compare = compare1
#ifdef LIFTED_FUNCTOR_CLASSES
instance (Ord1 f) => Ord1 (Cofree f) where
liftCompare cmp = go
where
go (a :< as) (b :< bs) = cmp a b `mappend` liftCompare go as bs
#else
instance (Functor f, Ord1 f) => Ord1 (Cofree f) where
compare1 (a :< as) (b :< bs) = case compare a b of
LT -> LT
EQ -> compare1 (fmap Lift1 as) (fmap Lift1 bs)
GT -> GT
#endif
instance Foldable f => Foldable (Cofree f) where
foldMap f = go where
go (a :< as) = f a `mappend` foldMap go as
{-# INLINE foldMap #-}
#if __GLASGOW_HASKELL__ >= 709
length = go 0 where
go s (_ :< as) = foldl' go (s + 1) as
#endif
instance Foldable1 f => Foldable1 (Cofree f) where
foldMap1 f = go where
go (a :< as) = f a <> foldMap1 go as
{-# INLINE foldMap1 #-}
instance Traversable f => Traversable (Cofree f) where
traverse f = go where
go (a :< as) = (:<) <$> f a <*> traverse go as
{-# INLINE traverse #-}
instance Traversable1 f => Traversable1 (Cofree f) where
traverse1 f = go where
go (a :< as) = (:<) <$> f a <.> traverse1 go as
{-# INLINE traverse1 #-}
#if __GLASGOW_HASKELL__ < 707
instance (Typeable1 f) => Typeable1 (Cofree f) where
typeOf1 dfa = mkTyConApp cofreeTyCon [typeOf1 (f dfa)]
where
f :: Cofree f a -> f a
f = undefined
instance (Typeable1 f, Typeable a) => Typeable (Cofree f a) where
typeOf = typeOfDefault
cofreeTyCon :: TyCon
#if __GLASGOW_HASKELL__ < 704
cofreeTyCon = mkTyCon "Control.Comonad.Cofree.Cofree"
#else
cofreeTyCon = mkTyCon3 "free" "Control.Comonad.Cofree" "Cofree"
#endif
{-# NOINLINE cofreeTyCon #-}
instance
( Typeable1 f
, Data (f (Cofree f a))
, Data a
) => Data (Cofree f a) where
gfoldl f z (a :< as) = z (:<) `f` a `f` as
toConstr _ = cofreeConstr
gunfold k z c = case constrIndex c of
1 -> k (k (z (:<)))
_ -> error "gunfold"
dataTypeOf _ = cofreeDataType
dataCast1 f = gcast1 f
cofreeConstr :: Constr
cofreeConstr = mkConstr cofreeDataType ":<" [] Infix
{-# NOINLINE cofreeConstr #-}
cofreeDataType :: DataType
cofreeDataType = mkDataType "Control.Comonad.Cofree.Cofree" [cofreeConstr]
{-# NOINLINE cofreeDataType #-}
#endif
instance ComonadHoist Cofree where
cohoist = hoistCofree
instance ComonadEnv e w => ComonadEnv e (Cofree w) where
ask = ask . lower
{-# INLINE ask #-}
instance ComonadStore s w => ComonadStore s (Cofree w) where
pos (_ :< as) = Class.pos as
{-# INLINE pos #-}
peek s (_ :< as) = extract (Class.peek s as)
{-# INLINE peek #-}
instance ComonadTraced m w => ComonadTraced m (Cofree w) where
trace m = trace m . lower
{-# INLINE trace #-}
_extract :: Functor f => (a -> f a) -> Cofree g a -> f (Cofree g a)
_extract f (a :< as) = (:< as) <$> f a
{-# INLINE _extract #-}
_unwrap :: Functor f => (g (Cofree g a) -> f (g (Cofree g a))) -> Cofree g a -> f (Cofree g a)
_unwrap f (a :< as) = (a :<) <$> f as
{-# INLINE _unwrap #-}
telescoped :: Functor f =>
[(Cofree g a -> f (Cofree g a)) -> g (Cofree g a) -> f (g (Cofree g a))] ->
(a -> f a) -> Cofree g a -> f (Cofree g a)
telescoped = Prelude.foldr (\l r -> _unwrap . l . r) _extract
{-# INLINE telescoped #-}
telescoped_ :: Functor f =>
[(Cofree g a -> f (Cofree g a)) -> g (Cofree g a) -> f (g (Cofree g a))] ->
(Cofree g a -> f (Cofree g a)) -> Cofree g a -> f (Cofree g a)
telescoped_ = Prelude.foldr (\l r -> _unwrap . l . r) id
{-# INLINE telescoped_ #-}
shoots :: (Applicative f, Traversable g) => (a -> f a) -> Cofree g a -> f (Cofree g a)
shoots f = go
where
#if __GLASGOW_HASKELL__ < 709
go xxs@(x :< xs) | null (toList xs) = pure xxs
#else
go xxs@(x :< xs) | null xs = pure xxs
#endif
| otherwise = (:<) <$> f x <*> traverse go xs
{-# INLINE shoots #-}
leaves :: (Applicative f, Traversable g) => (a -> f a) -> Cofree g a -> f (Cofree g a)
leaves f = go
where
#if __GLASGOW_HASKELL__ < 709
go (x :< xs) | null (toList xs) = (:< xs) <$> f x
#else
go (x :< xs) | null xs = (:< xs) <$> f x
#endif
| otherwise = (x :<) <$> traverse go xs
{-# INLINE leaves #-}