{-# 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.Traversing
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 (Traversing p, Traversing q) => Traversing (Procompose p q) where
traverse' (Procompose p q) = Procompose (traverse' p) (traverse' q)
{-# INLINE traverse' #-}
instance (Mapping p, Mapping q) => Mapping (Procompose p q) where
map' (Procompose p q) = Procompose (map' p) (map' q)
{-# INLINE map' #-}
instance (Corepresentable p, Corepresentable q) => Costrong (Procompose p q) where
unfirst = unfirstCorep
{-# INLINE unfirst #-}
unsecond = unsecondCorep
{-# INLINE unsecond #-}
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