packages feed

proarrow-0.1.0.0: src/Proarrow/Category/Monoidal/EndoProf.hs

{-# LANGUAGE AllowAmbiguousTypes #-}

-- | The monoidal category of endo-profunctors on @k@, with composition ('(:.:)'\/'Id') as the
-- tensor. The profunctor-specific counterpart of "Proarrow.Category.Monoidal.Endo" (in
-- @proarrow-equipment@), reusing "Proarrow.Path"\'s associators\/unitors.
--
-- A fresh wrapper, since "Proarrow.Profunctor.Instance.Day" already gives @k '+->' k@ a different
-- monoidal structure (Day convolution).
module Proarrow.Category.Monoidal.EndoProf where

import Data.Kind (Constraint)

import Proarrow.Category.Instance.Product ((:**:) (..))
import Proarrow.Category.Instance.Prof (Prof (..))
import Proarrow.Category.Instance.Sub (SUBCAT (..), Sub (..))
import Proarrow.Category.Monoidal (Monoidal (..), MonoidalProfunctor (..))
import Proarrow.Category.Monoidal.Action (MonoidalAction (..))
import Proarrow.Category.Monoidal.Distributive (Traversable)
import Proarrow.Category.Monoidal.Rev (REV (..), Rev (..))
import Proarrow.Core
  ( CAT
  , CategoryOf (..)
  , Is
  , Kind
  , OB
  , Profunctor (..)
  , Promonad (..)
  , UN
  , type (+->)
  , type (:&&:)
  , type (:~>)
  )
import Proarrow.Functor (FunctorForRep (..))
import Proarrow.Path qualified as Path
import Proarrow.Profunctor.Instance.Composition (o, (:.:))
import Proarrow.Profunctor.Instance.Identity (Id)
import Proarrow.Profunctor.Representable (Rep (..), Representable (..), index, repMap, repUniv, withObRep)

-- | An object of @'ENDO' k@ is an endo-profunctor @k +-> k@, i.e. (not necessarily
-- representable) a functor @k -> k@ under the profunctor encoding.
type ENDO :: Kind -> Kind
type data ENDO k = E (k +-> k)

-- | Morphisms of @'ENDO' k@ are natural transformations between the underlying profunctors.
type Endo :: CAT (ENDO k)
data Endo p q where
  Endo :: (Profunctor p, Profunctor q) => (p :~> q) -> Endo (E p) (E q)

instance (CategoryOf k) => Profunctor (Endo :: CAT (ENDO k)) where
  dimap (Endo l) (Endo r) (Endo f) = Endo (r . f . l)
  r \\ Endo _ = r

instance (CategoryOf k) => Promonad (Endo :: CAT (ENDO k)) where
  id = Endo Path.idN
  Endo f . Endo g = Endo (f . g)

-- | The category of endoprofunctors on @k@ and natural transformations between them.
instance (CategoryOf k) => CategoryOf (ENDO k) where
  type (~>) = Endo
  type Ob (a :: ENDO k) = (Is E a, Profunctor (UN E a))

instance (CategoryOf k) => MonoidalProfunctor (Endo :: CAT (ENDO k)) where
  one = Endo Path.idN
  Endo f ** Endo g = Endo (f `o` g)

instance (CategoryOf k) => Monoidal (ENDO k) where
  type Unit = E Id
  type E p ** E q = E (p :.: q)
  withOb2 @(E _) @(E _) r = r
  leftUnitor @(E p) = Endo (Path.leftUnitor @p)
  leftUnitorInv @(E p) = Endo (Path.leftUnitorInv @p)
  rightUnitor @(E p) = Endo (Path.rightUnitor @p)
  rightUnitorInv @(E p) = Endo (Path.rightUnitorInv @p)
  associator @(E p) @(E q) @(E r) = Endo (Path.associator @p @q @r)
  associatorInv @(E p) @(E q) @(E r) = Endo (Path.associatorInv @p @q @r)

-- | Lift a constraint on profunctors @k +-> k@ to the corresponding 'ENDO' objects.
type OnE :: ((k +-> k) -> Constraint) -> ENDO k -> Constraint
class (Is E a, c (UN E a)) => OnE c a

instance (Is E a, c (UN E a)) => OnE c a

-- | The subcategory of representable endo-profunctors, i.e. ordinary functors
-- @k -> k@ under the profunctor encoding. The most permissive restriction of 'ENDO' for
-- which an 'Proarrow.Category.Monoidal.Action.Act'ion makes sense (@'%'@ needs
-- 'Representable'), so every other 'MonoidalAction' on @k@ embeds into this one. See
-- 'TravSub' for a further restriction.
type RepSub k = SUBCAT (OnE Representable :: OB (ENDO k))

-- | The action of 'RepSub' on @k@ by application: @'Proarrow.Category.Monoidal.Action.Act' 'RepAction' ('SUB' ('E' f)) x = f '%' x@.
type RepAction = Rep RepAction'

data family RepAction' :: (RepSub k, k) +-> k
instance (CategoryOf k) => FunctorForRep (RepAction' :: (RepSub k, k) +-> k) where
  type RepAction' @ '(SUB (E p), x) = p % x
  fmap (Sub (Endo @p @q n) :**: (g :: x ~> y)) = index @q (n (repUniv @p @y)) . repMap @p g \\ g

instance (CategoryOf k) => MonoidalAction (RepAction :: (RepSub k, k) +-> k) where
  unitor = id
  unitorInv = id
  multiplicator @(SUB (E p)) @(SUB (E q)) @x = withObRep @q @x (withObRep @p @(q % x) id)
  multiplicatorInv @(SUB (E p)) @(SUB (E q)) @x = withObRep @q @x (withObRep @p @(q % x) id)

-- | The subcategory of representable, traversable endo-profunctors: the
-- functors 'Proarrow.Category.Monoidal.Distributive.repTraverse' can traverse with.
-- 'Monoidal' for free via "Proarrow.Category.Instance.Sub"\'s generic
-- @Monoidal (SUBCAT ob)@, since both 'Representable' and 'Traversable' already have
-- instances closing them under @:.:@\/'Id'.
type TravSub k = SUBCAT (OnE (Representable :&&: Traversable) :: OB (ENDO k))

-- | The action of 'TravSub' on @k@ by application: @'Proarrow.Category.Monoidal.Action.Act' 'TravAction' ('SUB' ('E' f)) x = f '%' x@.
type TravAction = Rep TravAction'

data family TravAction' :: (TravSub k, k) +-> k
instance (CategoryOf k) => FunctorForRep (TravAction' :: (TravSub k, k) +-> k) where
  type TravAction' @ '(SUB (E p), x) = p % x
  fmap (Sub (Endo @p @q n) :**: (g :: x ~> y)) = index @q (n (repUniv @p @y)) . repMap @p g \\ g

instance (CategoryOf k) => MonoidalAction (TravAction :: (TravSub k, k) +-> k) where
  unitor = id
  unitorInv = id
  multiplicator @(SUB (E p)) @(SUB (E q)) @x = withObRep @q @x (withObRep @p @(q % x) id)
  multiplicatorInv @(SUB (E p)) @(SUB (E q)) @x = withObRep @q @x (withObRep @p @(q % x) id)

-- | Endo-profunctors on @x@ act on profunctors @x '+->' h@ by precomposition:
-- @'Proarrow.Category.Monoidal.Action.Act' 'Precomp' ('E' g) q = q ':.:' g@. Since the acted-upon
-- kind is the whole profunctor kind, @g@ need not be 'Representable' (unlike 'RepAction'\/
-- 'TravAction'); only @'Rep' 'Precomp'@ is, automatically. So 'Proarrow.Squares.toOptic' can turn
-- any 'Proarrow.Squares.EqpOptic' into a 'Proarrow.Optic.Optic'.
--
-- The index category is @'REV' ('ENDO' x)@ because precomposing twice applies the actions in the
-- reverse of the order in which @'Proarrow.Category.Monoidal.**'@ on @'ENDO' x@ composes them.
data family Precomp :: forall x h. (REV (ENDO x), x +-> h) +-> (x +-> h)

instance (CategoryOf h, CategoryOf x) => FunctorForRep (Precomp :: (REV (ENDO x), x +-> h) +-> (x +-> h)) where
  type Precomp @ '(R (E g), q) = q :.: g
  fmap (Rev (Endo n) :**: Prof h') = Prof (h' `o` n)

instance (CategoryOf h, CategoryOf x) => MonoidalAction (Rep Precomp :: (REV (ENDO x), x +-> h) +-> (x +-> h)) where
  unitor = Prof Path.rightUnitor
  unitorInv = Prof Path.rightUnitorInv
  multiplicator @(R (E g)) @(R (E g')) @q = Prof (Path.associatorInv @q @g' @g)
  multiplicatorInv @(R (E g)) @(R (E g')) @q = Prof (Path.associator @q @g' @g)