packages feed

proarrow-0.1.0.0: src/Proarrow/Category/Instance/Rel.hs

{-# LANGUAGE AllowAmbiguousTypes #-}

-- Collected from https://www.clowderproject.com/tag/01D0.html

-- | __Relations__ as profunctors: a 'Relation' is a thin profunctor between discrete categories,
-- and this module collects the standard vocabulary of properties ('Functional', 'Total',
-- 'Injective', 'Surjective', 'Reflexive', 'Transitive', 'Symmetric', up to 'Preorder' and
-- 'Equivalence'), together with the 'Converse' relation.
module Proarrow.Category.Instance.Rel where

import Proarrow.Adjunction (Proadjunction (..))
import Proarrow.Category.Enriched.Dagger (DaggerProfunctor)
import Proarrow.Category.Enriched.Thin (DecidableProfunctor (..), Discrete, ThinProfunctor (..), mapDecision, withEq)
import Proarrow.Core (CategoryOf (..), Profunctor (..), Promonad (..), src, tgt, (:~>), type (+->))
import Proarrow.Profunctor.Corepresentable (Corepresentable (..))
import Proarrow.Profunctor.Instance.Composition ((:.:) (..))
import Proarrow.Profunctor.Representable (Representable (..), repUniv)

class (ThinProfunctor p, Discrete j, Discrete k) => Relation (p :: j +-> k)
instance (ThinProfunctor p, Discrete j, Discrete k) => Relation (p :: j +-> k)

-- | The converse relation: @'Converse' p a b@ relates @a@ to @b@ exactly when @p@ relates @b@
-- to @a@.
type Converse :: (j +-> k) -> (k +-> j)
data Converse p a b where
  Converse :: p b a -> Converse p a b

instance (Relation p) => Profunctor (Converse p) where
  dimap f g (Converse p) = withEq f (withEq g (Converse p))
  r \\ Converse p = r \\ p

instance (Relation p) => ThinProfunctor (Converse p) where
  type HasArrow (Converse p) a b = HasArrow p b a
  arr = Converse arr
  withArr (Converse p) r = withArr p r

instance (Relation p, DecidableProfunctor p) => DecidableProfunctor (Converse p) where
  type Holds (Converse p) a b = Holds p b a
  decide @a @b = mapDecision Converse (decide @p @b @a)
  toHolds (Converse p) r = toHolds p r

instance (Relation p, Representable p) => Corepresentable (Converse p) where
  type (Converse p) %% a = p % a
  coindex (Converse p) = withEq (index p) (src p)
  cotabulate f = withEq f (Converse (tabulate f))
  corepMap f = let fb = repMap @p (tgt f) in withEq f fb \\ fb

asImplication
  :: forall a b p q r
   . (Relation p, Relation q) => p :~> q -> (Ob a, Ob b, HasArrow p a b) => ((HasArrow q a b, Ob a, Ob b) => r) -> r
asImplication n = withArr (n (arr @p @a @b))

class (Relation p) => Functional p where
  isFunctional :: p :.: Converse p :~> (~>)

reprIsFunctional :: (Relation p, Representable p) => p :.: Converse p :~> (~>)
reprIsFunctional (p :.: Converse p') = withEq (index p) (withEq (index p') (src p))

class (Relation p) => Total p where
  isTotal :: (~>) :~> Converse p :.: p

reprIsTotal :: (Relation p, Representable p) => (~>) :~> Converse p :.: p
reprIsTotal f = withEq f (Converse repUniv :.: repUniv) \\ f

class (Relation p) => Injective p where
  isInjective :: Converse p :.: p :~> (~>)

class (Relation p) => Surjective p where
  isSurjective :: (~>) :~> p :.: Converse p

class (Relation p) => Reflexive p where
  isReflexive :: (~>) :~> p

class (Relation p) => Transitive p where
  isTransitive :: p :.: p :~> p

adjToConverse :: forall p q. (Relation p, Relation q, Proadjunction p q) => q :~> Converse p
adjToConverse q = Converse (case unit @p @q of _ :.: p -> withEq (counit (p :.: q)) p) \\ q

adjFromConverse :: forall p q. (Relation p, Relation q, Proadjunction p q) => Converse p :~> q
adjFromConverse (Converse @_ @_ @a p) = (case unit @p @q @a of q :.: _ -> withEq (counit (p :.: q)) q) \\ p

class (Relation p, Promonad p) => Preorder p
instance (Relation p, Promonad p) => Preorder p

class (Relation p, DaggerProfunctor p) => Symmetric p
instance (Relation p, DaggerProfunctor p) => Symmetric p

class (Preorder p, Symmetric p) => Equivalence p
instance (Preorder p, Symmetric p) => Equivalence p