packages feed

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

-- | The thin category of booleans: objects 'FLS' and 'TRU' with one non-identity arrow
-- @'FLS' '~>' 'TRU'@, the poset @False <= True@, a.k.a. the walking arrow. It is a core type.
-- Thin categories are enriched in it ("Proarrow.Category.Enriched.Thin"), so this module depends
-- on nothing but "Proarrow.Core". The further structure of @BOOL@ (conjunction as product and
-- tensor, disjunction as coproduct, closed, star-autonomous, (co)equalizers, pullbacks\/pushouts,
-- a parameterized NNO) is instantiated in the modules that define those classes.
module Proarrow.Category.Instance.Bool where

import Proarrow.Core (CAT, CategoryOf (..), Profunctor (..), Promonad (..), dimapDefault, type (+->))
import Prelude qualified as P

data BOOL = FLS | TRU

type Booleans :: CAT BOOL
data Booleans a b where
  Fls :: Booleans FLS FLS
  F2T :: Booleans FLS TRU
  Tru :: Booleans TRU TRU

deriving instance P.Eq (Booleans a b)
deriving instance P.Show (Booleans a b)

-- | Type-level conditional on a 'BOOL'.
type If :: BOOL -> k -> k -> k
type family If c t e where
  If TRU t e = t
  If FLS t e = e

-- | Negation; the 'Proarrow.Category.Monoidal.StarAutonomous.Dual' of @BOOL@.
type family Not (b :: BOOL) :: BOOL where
  Not FLS = TRU
  Not TRU = FLS

-- | GHC's own type-level 'P.Bool' (as produced by e.g. @<=?@ on 'GHC.TypeNats.Nat'), as a 'BOOL'.
type family FromBool (b :: P.Bool) :: BOOL where
  FromBool 'P.True = TRU
  FromBool 'P.False = FLS

class (IsBool (Not b)) => IsBool (b :: BOOL) where boolId :: b ~> b
instance IsBool FLS where boolId = Fls
instance IsBool TRU where boolId = Tru

-- | The category of 2 objects and one arrow between them, a.k.a. the walking arrow.
instance CategoryOf BOOL where
  type (~>) = Booleans
  type Ob b = IsBool b

instance Promonad Booleans where
  id = boolId
  Fls . Fls = Fls
  F2T . Fls = F2T
  Tru . F2T = F2T
  Tru . Tru = Tru

instance Profunctor Booleans where
  dimap = dimapDefault
  r \\ Fls = r
  r \\ F2T = r
  r \\ Tru = r

-- | @a <= b@ on the walking arrow, as a 'BOOL' again: the hom of the walking arrow is its own
-- internal hom.
type family BoolLeq (a :: BOOL) (b :: BOOL) :: BOOL where
  BoolLeq TRU FLS = FLS
  BoolLeq a b = TRU

-- | The four non-trivial profunctors @BOOL '+->' BOOL@, indexed by a pair of 'BOOL's selecting
-- whether the @FLS->FLS@ and @TRU->TRU@ heteromorphisms are present. @FLS->TRU@ always is.
type NonTrivialProfunctor :: (BOOL, BOOL) -> BOOL +-> BOOL
data NonTrivialProfunctor ft a b where
  FF :: NonTrivialProfunctor '(TRU, tt) FLS FLS
  FT :: NonTrivialProfunctor ft FLS TRU
  TT :: NonTrivialProfunctor '(ff, TRU) TRU TRU

deriving instance P.Eq (NonTrivialProfunctor ft a b)
deriving instance P.Show (NonTrivialProfunctor ft a b)

instance Profunctor (NonTrivialProfunctor ft) where
  dimap Fls Fls FF = FF
  dimap Fls F2T FF = FT
  dimap Fls Tru FT = FT
  dimap F2T Tru TT = FT
  dimap Tru Tru TT = TT
  dimap F2T Fls x = case x of {}
  dimap Tru Fls x = case x of {}
  dimap Tru F2T x = case x of {}
  dimap F2T F2T x = case x of {}
  r \\ FF = r
  r \\ FT = r
  r \\ TT = r

-- | Which heteromorphisms @'NonTrivialProfunctor' '(ff, tt)@ has.
type family NonTrivialHolds (ff :: BOOL) (tt :: BOOL) (a :: BOOL) (b :: BOOL) :: BOOL where
  NonTrivialHolds ff tt FLS FLS = ff
  NonTrivialHolds ff tt FLS TRU = TRU
  NonTrivialHolds ff tt TRU TRU = tt
  NonTrivialHolds ff tt TRU FLS = FLS