{-# LANGUAGE CPP #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE UndecidableInstances #-}
#if __GLASGOW_HASKELL__ >= 702 && __GLASGOW_HASKELL__ <= 708
{-# LANGUAGE Trustworthy #-}
#endif
module Data.Profunctor.Composition
(
Procompose(..)
, procomposed
, idl
, idr
, assoc
, eta
, mu
, stars, kleislis
, costars, cokleislis
, Rift(..)
, decomposeRift
) where
import Control.Arrow
import Control.Category
import Control.Comonad
import Control.Monad (liftM)
import Data.Functor.Compose
import Data.Profunctor
import Data.Profunctor.Adjunction
import Data.Profunctor.Monad
import Data.Profunctor.Rep
import Data.Profunctor.Sieve
import Data.Profunctor.Unsafe
import Prelude hiding ((.),id)
type Iso s t a b = forall p f. (Profunctor p, Functor f) => p a (f b) -> p s (f t)
data Procompose p q d c where
Procompose :: p x c -> q d x -> Procompose p q d c
instance ProfunctorFunctor (Procompose p) where
promap f (Procompose p q) = Procompose p (f q)
instance Category p => ProfunctorMonad (Procompose p) where
proreturn = Procompose id
projoin (Procompose p (Procompose q r)) = Procompose (p . q) r
procomposed :: Category p => Procompose p p a b -> p a b
procomposed (Procompose pxc pdx) = pxc . pdx
{-# INLINE procomposed #-}
instance (Profunctor p, Profunctor q) => Profunctor (Procompose p q) where
dimap l r (Procompose f g) = Procompose (rmap r f) (lmap l g)
{-# INLINE dimap #-}
lmap k (Procompose f g) = Procompose f (lmap k g)
{-# INLINE rmap #-}
rmap k (Procompose f g) = Procompose (rmap k f) g
{-# INLINE lmap #-}
k #. Procompose f g = Procompose (k #. f) g
{-# INLINE ( #. ) #-}
Procompose f g .# k = Procompose f (g .# k)
{-# INLINE ( .# ) #-}
instance Profunctor p => Functor (Procompose p q a) where
fmap k (Procompose f g) = Procompose (rmap k f) g
{-# INLINE fmap #-}
instance (Sieve p f, Sieve q g) => Sieve (Procompose p q) (Compose g f) where
sieve (Procompose g f) d = Compose $ sieve g <$> sieve f d
{-# INLINE sieve #-}
instance (Representable p, Representable q) => Representable (Procompose p q) where
type Rep (Procompose p q) = Compose (Rep q) (Rep p)
tabulate f = Procompose (tabulate id) (tabulate (getCompose . f))
{-# INLINE tabulate #-}
instance (Cosieve p f, Cosieve q g) => Cosieve (Procompose p q) (Compose f g) where
cosieve (Procompose g f) (Compose d) = cosieve g $ cosieve f <$> d
{-# INLINE cosieve #-}
instance (Corepresentable p, Corepresentable q) => Corepresentable (Procompose p q) where
type Corep (Procompose p q) = Compose (Corep p) (Corep q)
cotabulate f = Procompose (cotabulate (f . Compose)) (cotabulate id)
{-# INLINE cotabulate #-}
instance (Strong p, Strong q) => Strong (Procompose p q) where
first' (Procompose x y) = Procompose (first' x) (first' y)
{-# INLINE first' #-}
second' (Procompose x y) = Procompose (second' x) (second' y)
{-# INLINE second' #-}
instance (Choice p, Choice q) => Choice (Procompose p q) where
left' (Procompose x y) = Procompose (left' x) (left' y)
{-# INLINE left' #-}
right' (Procompose x y) = Procompose (right' x) (right' y)
{-# INLINE right' #-}
instance (Closed p, Closed q) => Closed (Procompose p q) where
closed (Procompose x y) = Procompose (closed x) (closed y)
{-# INLINE closed #-}
instance (Corepresentable p, Corepresentable q) => Costrong (Procompose p q) where
unfirst = unfirstCorep
unsecond = unsecondCorep
idl :: Profunctor q => Iso (Procompose (->) q d c) (Procompose (->) r d' c') (q d c) (r d' c')
idl = dimap (\(Procompose g f) -> rmap g f) (fmap (Procompose id))
idr :: Profunctor q => Iso (Procompose q (->) d c) (Procompose r (->) d' c') (q d c) (r d' c')
idr = dimap (\(Procompose g f) -> lmap f g) (fmap (`Procompose` id))
assoc :: Iso (Procompose p (Procompose q r) a b) (Procompose x (Procompose y z) a b)
(Procompose (Procompose p q) r a b) (Procompose (Procompose x y) z a b)
assoc = dimap (\(Procompose f (Procompose g h)) -> Procompose (Procompose f g) h)
(fmap (\(Procompose (Procompose f g) h) -> Procompose f (Procompose g h)))
stars :: Functor g
=> Iso (Procompose (Star f ) (Star g ) d c )
(Procompose (Star f') (Star g') d' c')
(Star (Compose g f ) d c )
(Star (Compose g' f') d' c')
stars = dimap hither (fmap yon) where
hither (Procompose (Star xgc) (Star dfx)) = Star (Compose . fmap xgc . dfx)
yon (Star dfgc) = Procompose (Star id) (Star (getCompose . dfgc))
costars :: Functor f
=> Iso (Procompose (Costar f ) (Costar g ) d c )
(Procompose (Costar f') (Costar g') d' c')
(Costar (Compose f g ) d c )
(Costar (Compose f' g') d' c')
costars = dimap hither (fmap yon) where
hither (Procompose (Costar gxc) (Costar fdx)) = Costar (gxc . fmap fdx . getCompose)
yon (Costar dgfc) = Procompose (Costar (dgfc . Compose)) (Costar id)
kleislis :: Monad g
=> Iso (Procompose (Kleisli f ) (Kleisli g ) d c )
(Procompose (Kleisli f') (Kleisli g') d' c')
(Kleisli (Compose g f ) d c )
(Kleisli (Compose g' f') d' c')
kleislis = dimap hither (fmap yon) where
hither (Procompose (Kleisli xgc) (Kleisli dfx)) = Kleisli (Compose . liftM xgc . dfx)
yon (Kleisli dfgc) = Procompose (Kleisli id) (Kleisli (getCompose . dfgc))
cokleislis :: Functor f
=> Iso (Procompose (Cokleisli f ) (Cokleisli g ) d c )
(Procompose (Cokleisli f') (Cokleisli g') d' c')
(Cokleisli (Compose f g ) d c )
(Cokleisli (Compose f' g') d' c')
cokleislis = dimap hither (fmap yon) where
hither (Procompose (Cokleisli gxc) (Cokleisli fdx)) = Cokleisli (gxc . fmap fdx . getCompose)
yon (Cokleisli dgfc) = Procompose (Cokleisli (dgfc . Compose)) (Cokleisli id)
newtype Rift p q a b = Rift { runRift :: forall x. p b x -> q a x }
instance ProfunctorFunctor (Rift p) where
promap f (Rift g) = Rift (f . g)
instance Category p => ProfunctorComonad (Rift p) where
proextract (Rift f) = f id
produplicate (Rift f) = Rift $ \p -> Rift $ \q -> f (q . p)
instance (Profunctor p, Profunctor q) => Profunctor (Rift p q) where
dimap ca bd f = Rift (lmap ca . runRift f . lmap bd)
{-# INLINE dimap #-}
lmap ca f = Rift (lmap ca . runRift f)
{-# INLINE lmap #-}
rmap bd f = Rift (runRift f . lmap bd)
{-# INLINE rmap #-}
bd #. f = Rift (\p -> runRift f (p .# bd))
{-# INLINE ( #. ) #-}
f .# ca = Rift (\p -> runRift f p .# ca)
{-# INLINE (.#) #-}
instance Profunctor p => Functor (Rift p q a) where
fmap bd f = Rift (runRift f . lmap bd)
{-# INLINE fmap #-}
instance p ~ q => Category (Rift p q) where
id = Rift id
{-# INLINE id #-}
Rift f . Rift g = Rift (g . f)
{-# INLINE (.) #-}
decomposeRift :: Procompose p (Rift p q) :-> q
decomposeRift (Procompose p (Rift pq)) = pq p
{-# INLINE decomposeRift #-}
instance ProfunctorAdjunction (Procompose p) (Rift p) where
counit (Procompose p (Rift pq)) = pq p
unit q = Rift $ \p -> Procompose p q
eta :: (Profunctor p, Category p) => (->) :-> p
eta f = rmap f id
mu :: Category p => Procompose p p :-> p
mu (Procompose f g) = f . g