proarrow-0.1.0.0: src/Proarrow/Profunctor/Instance/Exponential.hs
{-# OPTIONS_GHC -Wno-orphans #-}
-- | The internal hom of the category of profunctors under the /product/: a @(p ':~>:' q) a b@ is a
-- natural family of maps @p c d -> q c d@ available at @a@\/@b@, making @'PROD' (j +-> k)@ 'Closed'.
-- @j +-> k@ itself is 'Closed' too, but for Day convolution and with a different hom (see
-- "Proarrow.Profunctor.Instance.Day"). The 'PROD' wrapper keeps the two apart.
module Proarrow.Profunctor.Instance.Exponential where
import Proarrow.Category.Enriched.Thin
( DecidableProfunctor (..)
, Decision (..)
, Discrete
, ThinProfunctor (..)
, noArrow
, withEq
)
import Proarrow.Category.Instance.Bool (BoolLeq)
import Proarrow.Category.Instance.Constraint (reifyExp, (:=>) (..), type (:-) (..))
import Proarrow.Category.Instance.Prof (Prof (..))
import Proarrow.Category.Instance.Sub (IsObProd, SUBCAT (..), Sub (..))
import Proarrow.Category.Monoidal.Closed (Closed (..))
import Proarrow.Core (CategoryOf (..), OB, Profunctor (..), Promonad (..), UN, (//), type (+->))
import Proarrow.Limit.BinaryProduct (HasBinaryProducts, PROD (..), Prod (..))
import Proarrow.Limit.Terminal (HasTerminalObject)
import Proarrow.Profunctor.Instance.Product ((:*:) (..))
data (p :~>: q) a b where
Exp :: (Ob a, Ob b) => (forall c d. c ~> a -> b ~> d -> p c d -> q c d) -> (p :~>: q) a b
instance (Profunctor p, Profunctor q) => Profunctor (p :~>: q) where
dimap l r (Exp f) = l // r // Exp \ca bd p -> f (l . ca) (bd . r) p
r \\ Exp{} = r
instance (CategoryOf j, CategoryOf k) => Closed (PROD (j +-> k)) where
type p ~~> q = PR (UN PR p :~>: UN PR q)
withObExp r = r
curry (Prod (Prof n)) = Prod (Prof \p -> p // Exp \ca bd q -> n (dimap ca bd p :*: q))
apply = Prod (Prof \(Exp f :*: q) -> f id id q \\ q)
Prod (Prof m) ^^^ Prod (Prof n) = Prod (Prof \(Exp f) -> Exp \ca bd p -> m (f ca bd (n p)))
-- | That a full subcategory of the profunctors contains the internal homs of its objects, as a
-- class with a single instance, so that it can be the head of the quantified constraint below.
-- 'Proarrow.Category.Instance.Sub.IsObProd' has the same shape for the product.
class (ob (p :~>: q)) => IsObExp (ob :: OB (j +-> k)) p q
instance (ob (p :~>: q)) => IsObExp ob p q
-- | And then the subcategory is closed, with the ambient exponential and nothing of its own,
-- just as its products are the ambient ones. @'Proarrow.Category.Enriched.Finitary.Topos.FINITARY'
-- j k@ is one instance, 'Proarrow.Category.Enriched.Finitary.Sheaf.SHEAVES' another. For the
-- first, a hom-set of natural transformations is finitary. For the second, an internal hom into a
-- sheaf is a sheaf.
instance
( CategoryOf j
, CategoryOf k
, HasTerminalObject (SUBCAT ob)
, HasBinaryProducts (SUBCAT ob)
, -- the product one again, as a constraint: 'apply' needs @ob@ of a product whose left factor is
-- an internal hom, which no @'Ob' _@ in scope mentions
forall p q. (ob p, ob q) => IsObProd ob p q
, forall p q. (ob p, ob q) => IsObExp ob p q
)
=> Closed (PROD (SUBCAT (ob :: OB (j +-> k))))
where
type p ~~> q = PR (SUB (UN SUB (UN PR p) :~>: UN SUB (UN PR q)))
withObExp r = r
curry (Prod (Sub (Prof n))) = Prod (Sub (Prof \p -> p // Exp \ca bd q -> n (dimap ca bd p :*: q)))
apply = Prod (Sub (Prof \(Exp f :*: q) -> f id id q \\ q))
Prod (Sub (Prof m)) ^^^ Prod (Sub (Prof n)) = Prod (Sub (Prof \(Exp f) -> Exp \ca bd p -> m (f ca bd (n p))))
instance (ThinProfunctor p, ThinProfunctor q, Discrete j, Discrete k) => ThinProfunctor (p :~>: q :: j +-> k) where
type HasArrow (p :~>: q) a b = (HasArrow p a b :=> HasArrow q a b)
arr @a @b = Exp \ca bd p -> withEq ca (withEq bd (withArr p (unEntails (entails @(HasArrow p a b) @(HasArrow q a b)) arr)))
withArr @a @b (Exp f) r = reifyExp (Entails @(HasArrow p a b) @(HasArrow q a b) (\r' -> withArr (f id id arr) r')) r
-- | Implication, decided: the exponential holds unless @p@ holds and @q@ does not. Against @p@ an
-- arrow of @p@ is refuted by 'noArrow'.
instance
(DecidableProfunctor p, DecidableProfunctor q, Discrete j, Discrete k)
=> DecidableProfunctor (p :~>: q :: j +-> k)
where
type Holds (p :~>: q) a b = BoolLeq (Holds p a b) (Holds q a b)
decide @a @b = case (decide @p @a @b, decide @q @a @b) of
(_, Yes y) -> Yes (Exp \ca bd _ -> withEq ca (withEq bd y))
(No, No) -> Yes (Exp \ca bd x -> withEq ca (withEq bd (noArrow x)))
(Yes _, No) -> No
toHolds @a @b (Exp f) r = case decide @p @a @b of
Yes x -> toHolds (f id id x) r
No -> r