{-# LANGUAGE ExistentialQuantification #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE InstanceSigs #-}
{-# LANGUAGE PolyKinds #-}
{-# LANGUAGE QuantifiedConstraints #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeOperators #-}
-- | Comonads in the cateogory of @Functor@s.
module FComonad
( type (~>),
FFunctor (..),
FComonad (..),
fduplicate
) where
import Control.Comonad
import Data.Functor.Product
import Data.Functor.Compose
import qualified Data.Bifunctor.Sum as Bi
import Control.Comonad.Trans.Identity
import Control.Comonad.Env ( EnvT(..) )
import Control.Comonad.Traced (TracedT(..))
import Control.Comonad.Cofree (Cofree(..))
import qualified Control.Comonad.Cofree as Cofree
import FFunctor
import Data.Coerce (coerce)
-- | @FComonad@ is to 'FFunctor' what 'Comonad' is to 'Functor'.
class FFunctor ff => FComonad ff where
fextract :: Functor g => ff g ~> g
fextend :: (Functor g, Functor h) => (ff g ~> h) -> (ff g ~> ff h)
fduplicate :: (FComonad ff, Functor g) => ff g ~> ff (ff g)
fduplicate = fextend id
instance FComonad IdentityT where
fextract = coerce
fextend tr = coerce . tr
instance Functor f => FComonad (Product f) where
fextract (Pair _ g) = g
fextend tr fg@(Pair f _) = Pair f (tr fg)
instance Comonad f => FComonad (Compose f) where
fextract = extract . getCompose
fextend tr = Compose . extend (tr . Compose) . getCompose
instance (FComonad ff, FComonad gg) => FComonad (Bi.Sum ff gg) where
fextract (Bi.L2 ffx) = fextract ffx
fextract (Bi.R2 ggx) = fextract ggx
fextend tr ffgg = case ffgg of
Bi.L2 ffx -> Bi.L2 (fextend (tr . Bi.L2) ffx)
Bi.R2 ggx -> Bi.R2 (fextend (tr . Bi.R2) ggx)
instance FComonad (EnvT e) where
fextract (EnvT _ gx) = gx
fextend tr eg@(EnvT e _) = EnvT e (tr eg)
instance Monoid m => FComonad (TracedT m) where
fextract (TracedT g) = ($ mempty) <$> g
fextend tr (TracedT g) = TracedT $ tr (TracedT $ fmap (\k m1 m2 -> k (m1 <> m2)) g)
instance FComonad Cofree where
fextract :: Functor g => Cofree g ~> g
fextract = fmap extract . Cofree.unwrap
fextend :: (Functor g, Functor h) => (Cofree g ~> h) -> (Cofree g ~> Cofree h)
fextend tr = ffmap tr . Cofree.section
{-
fextract $ fduplicate gs
= fextract $ extract gs :< fmap fduplicate_ (duplicate gs)
= fmap extract (fmap fduplicate_ (duplicate gs))
= fmap (extract . fduplicate_) (duplicate gs)
= fmap extract (duplicate gs)
= gs
ffmap fextract $ fduplicate gs
= ffmap fextract $ extract gs :< fmap fduplicate_ (duplicate gs)
= extract gs :< (fmap (ffmap fextract) . fextract . fmap fduplicate_) (duplicate gs)
= extract gs :< (fmap (ffmap fextract . fduplicate_) . fextract) (duplicate gs)
-- gs = (a :< gs')
= extract (a :< gs') :< fmap (ffmap fextract . fduplicate_) (fextract (duplicate (a :< gs')))
= a :< fmap (ffmap fextract . fduplicate_) (fextract ((a :< gs') :< fmap duplicate gs'))
= a :< fmap (ffmap fextract . fduplicate_) (fmap extract (fmap duplicate gs'))
= a :< fmap (ffmap fextract . fduplicate_) gs'
ffmap fextract . fduplicate_
= let go (a :< gs) = a :< fmap go gs
in go
= id
-}