packages feed

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

{-# LANGUAGE AllowAmbiguousTypes #-}

-- | Actions of a monoidal category on another category: a 'MonoidalAction' is a representable
-- profunctor @t :: (m, k) '+->' k@ acting as @'Act' t a x@, with 'unitor' and 'multiplicator'
-- coherences. Main instances are the tensor acting on its own category, the cartesian product
-- ('ProdAction') and the coproduct ('CoprodAction').
module Proarrow.Category.Monoidal.Action where

import Data.Kind (Constraint)

import Proarrow.Category.Instance.Opposite (OPPOSITE (..), Op (..))
import Proarrow.Category.Instance.Product ((:**:) (..))
import Proarrow.Category.Instance.Sub (SUBCAT (..), Sub (..))
import Proarrow.Category.Instance.Unit qualified as U
import Proarrow.Category.Monoidal (Monoidal (..), Tensor)
import Proarrow.Colimit.BinaryCoproduct
  ( COPROD (..)
  , Coprod (..)
  , HasBinaryCoproducts (..)
  , HasCoproducts
  , associatorCoprod
  , associatorCoprodInv
  , leftUnitorCoprod
  , leftUnitorCoprodInv
  )
import Proarrow.Core (CategoryOf (..), OB, Promonad (..), obj, type (+->))
import Proarrow.Functor (FunctorForRep (..))
import Proarrow.Limit.BinaryProduct
  ( HasBinaryProducts (..)
  , HasProducts
  , PROD (..)
  , Prod (..)
  , associatorProd
  , associatorProdInv
  , leftUnitorProd
  , leftUnitorProdInv
  )
import Proarrow.Profunctor.Representable (Rep (..), Representable (..))

type Act :: (m, k) +-> k -> m -> k -> k
type Act t a x = t % '(a, x)

type MonoidalAction :: forall {m} {k}. (m, k) +-> k -> Constraint

-- | An action of a monoidal category @m@ on a category @k@, given by a representable profunctor
-- @t@ whose functor is @'Act' t@. This is 'Monoidal' with the two sides allowed to differ: taking
-- @k = m@ and @t@ the tensor recovers it.
--
-- __Laws:__
--
-- The two isomorphisms must be mutually inverse:
--
-- * @'unitor' . 'unitorInv' = 'id'@ and @'unitorInv' . 'unitor' = 'id'@
-- * @'multiplicator' . 'multiplicatorInv' = 'id'@ and @'multiplicatorInv' . 'multiplicator' = 'id'@
--
-- natural in every argument (via 'actHom'), and coherent with the monoidal structure of @m@:
--
-- * Triangle: @'actHom' 'id' 'unitor' . 'multiplicator' = 'actHom' ('rightUnitor') 'id'@
-- * Pentagon: @'actHom' 'id' 'multiplicator' . 'multiplicator'
--   = 'multiplicator' . 'actHom' ('associator') 'id'@
--
-- "Proarrow.Testing.Laws" has no check for these laws.
class (Representable t, Monoidal m) => MonoidalAction (t :: (m, k) +-> k) where
  -- | Acting by the 'Unit' does nothing.
  unitor :: (Ob x) => Act t Unit x ~> x

  -- | Inverse to 'unitor'.
  unitorInv :: (Ob x) => x ~> Act t Unit x

  -- | Acting by a tensor is acting twice.
  multiplicator :: (Ob a, Ob b, Ob x) => Act t (a ** b) x ~> Act t a (Act t b x)

  -- | Inverse to 'multiplicator'.
  multiplicatorInv :: (Ob a, Ob b, Ob x) => Act t a (Act t b x) ~> Act t (a ** b) x

actHom :: (Representable t) => a ~> b -> x ~> y -> Act t a x ~> Act t b y
actHom @t l r = repMap @t (l :**: r)

composeActs
  :: forall {m} {k} t (x :: m) (y :: m) (c :: k) (a :: k) (b :: k)
   . (MonoidalAction t, Ob x, Ob y, Ob c)
  => a ~> Act t x b
  -> b ~> Act t y c
  -> a ~> Act t (x ** y) c
composeActs f g = multiplicatorInv @t @x @y @c . actHom @t (obj @x) g . f

decomposeActs
  :: forall {m} {k} t (x :: m) (y :: m) (c :: k) (a :: k) (b :: k)
   . (MonoidalAction t, Ob x, Ob y, Ob c)
  => Act t y c ~> b
  -> Act t x b ~> a
  -> Act t (x ** y) c ~> a
decomposeActs f g = g . actHom @t (obj @x) f . multiplicator @t @x @y @c

-- | The dual of 'Act' partially applied at a fixed acted-on object: 'Act' fixes the acted-on
-- object and varies the index, this fixes the index @x@ and varies the acted-on object.
data family ActionAt :: (m, k) +-> k -> m -> k +-> k

instance (MonoidalAction act, Ob (x :: m)) => FunctorForRep (ActionAt act x :: k +-> k) where
  type ActionAt act x @ a = Act act x a
  fmap = actHom @act (obj @x)

data family NoAction :: ((), k) +-> k
instance (CategoryOf k) => FunctorForRep (NoAction :: ((), k) +-> k) where
  type NoAction @ '(a, x) = x
  fmap (U.Unit :**: f) = f
instance (CategoryOf k) => MonoidalAction (Rep NoAction :: ((), k) +-> k) where
  unitor = id
  unitorInv = id
  multiplicator = id
  multiplicatorInv = id

data family OpAction :: (m, k) +-> k -> (OPPOSITE m, OPPOSITE k) +-> OPPOSITE k
instance (Representable (t :: (m, k) +-> k), CategoryOf m) => FunctorForRep (OpAction t) where
  type OpAction t @ '(OP a, OP x) = OP (t % '(a, x))
  fmap (Op l :**: Op r) = Op (actHom @t l r)
instance (MonoidalAction t) => MonoidalAction (Rep (OpAction t)) where
  unitor = Op (unitorInv @t)
  unitorInv = Op (unitor @t)
  multiplicator @(OP a) @(OP b) @(OP x) = Op (multiplicatorInv @t @a @b @x)
  multiplicatorInv @(OP a) @(OP b) @(OP x) = Op (multiplicator @t @a @b @x)

type SubAction ob t = Rep (SubAction' ob t)
data family SubAction' :: forall (ob :: OB m) -> (m, k) +-> k -> (SUBCAT ob, k) +-> k
instance (Monoidal k, Monoidal (SUBCAT (ob :: OB k)), Representable t) => FunctorForRep (SubAction' ob t) where
  type SubAction' ob t @ '(SUB a, x) = t % '(a, x)
  fmap (Sub f :**: g) = repMap @t (f :**: g)
instance (Monoidal k, Monoidal (SUBCAT (ob :: OB k)), MonoidalAction t) => MonoidalAction (SubAction ob t) where
  unitor = unitor @t
  unitorInv = unitorInv @t
  multiplicator @(SUB p) @(SUB q) @x = multiplicator @t @p @q @x
  multiplicatorInv @(SUB p) @(SUB q) @x = multiplicatorInv @t @p @q @x

instance (Monoidal k) => MonoidalAction (Tensor :: (k, k) +-> k) where
  unitor = leftUnitor @k
  unitorInv = leftUnitorInv @k
  multiplicator @a @b @x = associator @k @a @b @x
  multiplicatorInv @a @b @x = associatorInv @k @a @b @x

type ProdAction = Rep ProdAction'
data family ProdAction' :: (PROD k, k) +-> k
instance (HasProducts k) => FunctorForRep (ProdAction' :: (PROD k, k) +-> k) where
  type ProdAction' @ '(PR a, b) = a && b
  fmap (Prod p :**: q) = p *** q
instance (HasProducts k) => MonoidalAction (ProdAction :: (PROD k, k) +-> k) where
  unitor = leftUnitorProd
  unitorInv = leftUnitorProdInv
  multiplicator @(PR a) @(PR b) @x = associatorProd @a @b @x
  multiplicatorInv @(PR a) @(PR b) @x = associatorProdInv @a @b @x

type CoprodAction = Rep CoprodAction'
data family CoprodAction' :: (COPROD k, k) +-> k
instance (HasCoproducts k) => FunctorForRep (CoprodAction' :: (COPROD k, k) +-> k) where
  type CoprodAction' @ '(COPR a, x) = a || x
  fmap (Coprod l :**: r) = l +++ r
instance (HasCoproducts k) => MonoidalAction (CoprodAction :: (COPROD k, k) +-> k) where
  unitor = leftUnitorCoprod
  unitorInv = leftUnitorCoprodInv
  multiplicator @(COPR a) @(COPR b) @x = associatorCoprod @a @b @x
  multiplicatorInv @(COPR a) @(COPR b) @x = associatorCoprodInv @a @b @x