packages feed

proarrow-0.1.0.0: src/Proarrow/Colimit/Copower.hs

{-# LANGUAGE AllowAmbiguousTypes #-}
{-# OPTIONS_GHC -Wno-orphans #-}

-- | Copowers (tensors) of a category enriched in @v@: 'Copowered' provides @n '*.' a@, characterized by
-- the isomorphism between @(n '*.' a) '~>' b@ and @n '~>' 'HomObj' v a b@ ('copower'\/'uncopower').
module Proarrow.Colimit.Copower where

import Data.Kind (Type)
import Prelude (type (~))

import Proarrow.Category.Enriched (Enriched, GenArrow (..), HomObj, comp, underlying)
import Proarrow.Category.Enriched.Finitary (Elt (..))
import Proarrow.Category.Instance.FinHask (FINHASK, arr)
import Proarrow.Category.Instance.Opposite (OPPOSITE (..), Op (..))
import Proarrow.Category.Instance.Product ((:**:) (..))
import Proarrow.Category.Instance.Prof (Prof (..))
import Proarrow.Category.Instance.Unit (Unit (..))
import Proarrow.Category.Monoidal (Monoidal (..), SymMonoidal, rightUnitorInvWith, type (**))
import Proarrow.Category.Monoidal.Closed (Closed (..), uncurry)
import Proarrow.Core (CategoryOf (..), Ob, Profunctor (dimap, (\\)), Promonad (..), obj, (//), type (+->))
import Proarrow.Limit.Power (Powered (..))
import Proarrow.Profunctor.Corepresentable (Corepresentable (..))

-- | Categories copowered over @v@.
class (Enriched v k) => Copowered v k where
  type (n :: v) *. (a :: k) :: k
  withObCopower :: (Ob (a :: k), Ob (n :: v)) => ((Ob (n *. a)) => r) -> r
  copower :: (Ob (a :: k), Ob b) => n ~> HomObj v a b -> (n *. a) ~> b
  uncopower :: (Ob (a :: k), Ob n) => (n *. a) ~> b -> n ~> HomObj v a b

mapCobase :: forall {k} {v} (a :: k) b (n :: v). (Copowered v k, Ob n) => a ~> b -> n *. a ~> n *. b
mapCobase f =
  f //
    withObCopower @v @k @b @n
      ( copower @v @k @a @(n *. b) @n
          (let g = uncopower @v @k @b @n id in g // comp @v @a @b @(n *. b) . rightUnitorInvWith (underlying @v f) . g)
      )

mapCopower :: forall {k} {v} (a :: k) (n :: v) m. (Copowered v k, Ob a) => (n ~> m) -> n *. a ~> m *. a
mapCopower f = withObCopower @v @k @a @m (copower @v @k @a @(m *. a) @n (uncopower @v @k @a id . f)) \\ f

selfCopowered :: forall {v} (a :: v) b n. (Closed v, SymMonoidal v, Ob a, Ob b) => n ~> (a ~~> b) -> n ** a ~> b
selfCopowered = uncurry @a

selfUncopowered :: forall {v} (a :: v) b n. (Closed v, SymMonoidal v, Ob a, Ob n) => n ** a ~> b -> n ~> (a ~~> b)
selfUncopowered = curry @_ @n @a @b

instance Copowered Type Type where
  type n *. a = (n, a)
  withObCopower r = r
  copower f (n, a) = f n a
  uncopower f n a = f (n, a)

instance Copowered Type () where
  type n *. a = '()
  withObCopower r = r
  copower _ = Unit
  uncopower Unit _ = Unit

instance (Copowered Type j, Copowered Type k) => Copowered Type (j, k) where
  type n *. '(a, b) = '(n *. a, n *. b)
  withObCopower @'(a, b) @n r = withObCopower @_ @j @a @n (withObCopower @_ @k @b @n r)
  copower f = copower (\n -> fstK (f n)) :**: copower (\n -> sndK (f n))
  uncopower (f :**: g) n = uncopower f n :**: uncopower g n

data (n :*.: p) a b where
  Copower :: n -> p a b -> (n :*.: p) a b
instance (Profunctor p) => Profunctor (n :*.: p) where
  dimap l r (Copower n p) = Copower n (dimap l r p)
  r \\ Copower _ p = r \\ p
instance (CategoryOf j, CategoryOf k) => Copowered Type (j +-> k) where
  type n *. a = n :*.: a
  withObCopower r = r
  copower f = Prof \(Copower n p) -> unProf (f n) p
  uncopower (Prof f) n = Prof \p -> f (Copower n p)

-- | Kept with the class, for the same reason as 'Powered' 'FINHASK' 'FINHASK'.
instance Copowered FINHASK FINHASK where
  type n *. a = n ** a
  withObCopower @a @n r = withOb2 @_ @a @n r
  copower @a @b f = selfCopowered @a @b (arr unElt . f)
  uncopower f = (\g -> arr Elt . g) (selfUncopowered f) \\ f

class (HomObj v (OP a) (OP b) ~ HomObj v b a) => HomObjOp v a b
instance (HomObj v (OP a) (OP b) ~ HomObj v b a) => HomObjOp v a b

instance (Copowered v k, Enriched v (OPPOSITE k), forall (a :: k) b. HomObjOp v a b) => Powered v (OPPOSITE k) where
  type OP a ^ n = OP (n *. a)
  withObPower @(OP a) @n r = withObCopower @v @k @a @n r
  power @(OP a) @(OP b) f = Op (copower @v @k @b @a f)
  unpower @(OP a) (Op f) = uncopower @v @k @a f

instance (Powered v k, Enriched v (OPPOSITE k), forall (a :: k) b. HomObjOp v a b) => Copowered v (OPPOSITE k) where
  type n *. OP a = OP (a ^ n)
  withObCopower @(OP a) @n r = withObPower @v @k @a @n r
  copower @(OP a) @(OP b) f = Op (power @v @k @b @a f)
  uncopower @(OP a) (Op f) = unpower @v @k @a f

instance (Copowered v k, Ob (n :: v)) => Corepresentable (GenArrow (OP (n :: v)) :: k +-> k) where
  type GenArrow (OP n) %% a = n *. a
  coindex (GenArrow @a @b f) = copower @v @k @a @b f
  corepUniv @a = withObCopower @v @k @a @n (GenArrow (uncopower @v @k @a (obj @(n *. a))))