proarrow-0.1.0.0: src/Proarrow/Category/Instance/Sub.hs
-- | __Full subcategories__: the kind @'SUBCAT' ob@ restricts a category to the objects satisfying
-- the predicate @ob@, with 'Sub' wrapping the underlying arrows unchanged. This is how object
-- constraints beyond a kind's own 'Ob' are imposed (e.g. the category of representable profunctors
-- in "Proarrow.Category.Instance.Rep").
module Proarrow.Category.Instance.Sub where
import Data.Kind (Constraint)
import Proarrow.Category.Instance.Prof (Prof (..))
import Proarrow.Category.Monoidal (Monoidal (..), MonoidalProfunctor (..), SymMonoidal (..))
import Proarrow.Core (CAT, CategoryOf (..), Kind, OB, Profunctor (..), Promonad (..), UN, WrappedOb, type (+->))
import Proarrow.Functor (FunctorForRep (..))
import Proarrow.Limit.BinaryProduct (HasBinaryProducts (..))
import Proarrow.Limit.Terminal (HasTerminalObject (..))
import Proarrow.Profunctor.Representable (Representable (..))
import Prelude (type (~))
import Proarrow.Category.Instance.Bool (BOOL (..), Booleans (..))
type SUBCAT :: forall {k}. OB k -> Kind
type data SUBCAT (ob :: OB k) = SUB k
-- | Wraps an arrow whose endpoints satisfy the predicate @ob@: the arrows of the full
-- subcategory 'SUBCAT'.
type Sub :: CAT k -> CAT (SUBCAT (ob :: OB k))
data Sub p a b where
Sub :: (ob a, ob b) => {unSub :: p a b} -> Sub p (SUB a :: SUBCAT ob) (SUB b)
instance (Profunctor p) => Profunctor (Sub p) where
dimap (Sub l) (Sub r) (Sub p) = Sub (dimap l r p)
r \\ Sub p = r \\ p
instance (Promonad p) => Promonad (Sub p) where
id = Sub id
Sub f . Sub g = Sub (f . g)
-- | The subcategory with objects with instances of the given constraint `ob`.
instance (CategoryOf k) => CategoryOf (SUBCAT (ob :: OB k)) where
type (~>) = Sub (~>)
type Ob (a :: SUBCAT ob) = (WrappedOb SUB a, ob (UN SUB a))
type On :: (k -> Constraint) -> forall (ob :: OB k) -> SUBCAT ob -> Constraint
class (c (UN SUB a)) => (c `On` ob) a
instance (c (UN SUB a)) => (c `On` ob) a
class (ob (a ** b)) => IsObMult (ob :: OB k) a b
instance (ob (a ** b)) => IsObMult (ob :: OB k) a b
-- | The same for the /product/: that the subcategory contains the products of its objects, as a
-- class with a single instance so that it can be the head of a quantified constraint.
class (ob (a && b)) => IsObProd (ob :: OB k) a b
instance (ob (a && b)) => IsObProd (ob :: OB k) a b
-- | A full subcategory has the ambient finite products as soon as it contains them, as the
-- quantified constraint says. The projections and pairing are the ambient ones under 'Sub'.
--
-- There is no exponential at an arbitrary kind: neither @'withObExp'@ nor @curry@ discharges
-- through @'Proarrow.Limit.BinaryProduct.PROD' k@\'s round trip
-- @'Proarrow.Core.UN' PR (PR a '~~>' PR b)@.
-- For subcategories of profunctors see
-- @'Proarrow.Category.Monoidal.Closed.Closed' ('Proarrow.Limit.BinaryProduct.PROD' ('SUBCAT' ob))@
-- in "Proarrow.Profunctor.Instance.Exponential".
instance (HasTerminalObject k, ob (TerminalObject :: k)) => HasTerminalObject (SUBCAT (ob :: OB k)) where
type TerminalObject @(SUBCAT (ob :: OB k)) = SUB (TerminalObject :: k)
terminate = Sub terminate
instance
(HasBinaryProducts k, forall a b. (ob a, ob b) => IsObProd ob a b)
=> HasBinaryProducts (SUBCAT (ob :: OB k))
where
type (&&) @(SUBCAT (ob :: OB k)) a b = SUB (UN SUB a && UN SUB b)
withObProd @(SUB a) @(SUB b) r = withObProd @k @a @b r
fst @(SUB a) @(SUB b) = Sub (fst @k @a @b)
snd @(SUB a) @(SUB b) = Sub (snd @k @a @b)
Sub l &&& Sub r = Sub (l &&& r)
instance (MonoidalProfunctor p, SubMonoidal ob) => MonoidalProfunctor (Sub p :: CAT (SUBCAT (ob :: OB k))) where
one = Sub one
Sub f ** Sub g = Sub (f ** g)
class (Monoidal k, ob Unit, forall a b. (ob a, ob b) => IsObMult ob a b) => SubMonoidal (ob :: OB k)
instance (Monoidal k, ob Unit, forall a b. (ob a, ob b) => IsObMult ob a b) => SubMonoidal (ob :: OB k)
instance (SubMonoidal ob) => Monoidal (SUBCAT (ob :: OB k)) where
type Unit = SUB Unit
type a ** b = SUB (UN SUB a ** UN SUB b)
withOb2 @(SUB a) @(SUB b) r = withOb2 @k @a @b r
leftUnitor = Sub leftUnitor
leftUnitorInv = Sub leftUnitorInv
rightUnitor = Sub rightUnitor
rightUnitorInv = Sub rightUnitorInv
associator @(SUB a) @(SUB b) @(SUB c) = Sub (associator @_ @a @b @c)
associatorInv @(SUB a) @(SUB b) @(SUB c) = Sub (associatorInv @_ @a @b @c)
instance (SymMonoidal k, SubMonoidal ob) => SymMonoidal (SUBCAT (ob :: OB k)) where
swap @(SUB a) @(SUB b) = Sub (swap @k @a @b)
data family Forget :: forall (ob :: OB k) -> SUBCAT ob +-> k
instance (CategoryOf k) => FunctorForRep (Forget (ob :: OB k)) where
type Forget ob @ a = UN SUB a
fmap (Sub f) = f
instance (Representable p, forall a. (ob a) => ob (p % a)) => Representable (Sub p :: CAT (SUBCAT (ob :: OB k))) where
type Sub p % a = SUB (p % UN SUB a)
index (Sub p) = Sub (index p)
tabulate (Sub f) = Sub (tabulate f)
repMap (Sub f) = Sub (repMap @p f)
type FUN j k = SUBCAT (Representable :: OB (j +-> k))
(!) :: forall {j} {k} f g a b. f ~> (g :: FUN j k) -> a ~> b -> UN SUB f % a ~> UN SUB g % b
Sub (Prof n) ! ab = index @(UN SUB g) @_ @b (n (tabulate (repMap @(UN SUB f) ab))) \\ ab
-- | The arrow category of @k@ as functor category from @2@ to @k@.
type ARROW k = FUN BOOL k
commSquare
:: forall {k} f g a b c d
. (a ~ f % FLS, b ~ f % TRU, c ~ g % FLS, d ~ g % TRU) => SUB f ~> (SUB g :: ARROW k) -> (a ~> b, b ~> d, a ~> c, c ~> d)
commSquare n = (repMap @f F2T, n ! Tru, n ! Fls, repMap @g F2T) \\ n