packages feed

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

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

-- | The __augmented simplex category__: objects are the finite ordinals (as type-level 'Nat's,
-- including the empty ordinal 'Z') and morphisms are order-preserving maps, built from the
-- constructors 'ZZ', 'Y' (skip a target) and 'X' (repeat a source). Ordinal sum makes it monoidal,
-- and it is the walking monoid: monoids in a monoidal category correspond to monoidal functors out
-- of it.
module Proarrow.Category.Instance.Simplex (module Proarrow.Category.Instance.Simplex, Nat (..)) where

import Data.Fin (Fin (..))
import Data.Kind (Type)
import Data.Type.Nat (Nat (..), SNatI, type Plus)
import Data.Vec.Lazy (Vec (..))
import Prelude (Eq, Show (..), (++), type (~))

import Data.Typeable (Typeable)
import Proarrow.Category.Instance.Opposite (OPPOSITE (..), Op (..))
import Proarrow.Category.Monoidal (Monoidal (..), MonoidalProfunctor (..), Strictly, associatorDefault)
import Proarrow.Colimit.Initial (HasInitialObject (..))
import Proarrow.Core (CAT, CategoryOf (..), Profunctor (..), Promonad (..), dimapDefault, obj, src, type (+->))
import Proarrow.Functor (FunctorForRep (..))
import Proarrow.Limit.Terminal (HasTerminalObject (..))
import Proarrow.Monoid (Monoid (..))

type n + m = Plus n m

data SNat :: Nat -> Type where
  SZ :: SNat Z
  SS :: (IsNat n) => SNat (S n)
instance Show (SNat n) where
  show SZ = "Z"
  show (SS @n') = "S" ++ show (singNat @n')

class (a + S b ~ S (a + b), Strictly a) => Rules a b
instance (a + S b ~ S (a + b), Strictly a) => Rules a b

class (forall b. Rules a b, SNatI a, Typeable a) => IsNat (a :: Nat) where singNat :: SNat a
instance IsNat Z where singNat = SZ
instance (IsNat a) => IsNat (S a) where singNat = SS

type Simplex :: CAT Nat
data Simplex a b where
  ZZ :: Simplex Z Z
  Y :: Simplex x y -> Simplex x (S y)
  X :: Simplex x (S y) -> Simplex (S x) (S y)
deriving instance Eq (Simplex a b)
deriving instance Show (Simplex a b)

suc :: Simplex a b -> Simplex (S a) (S b)
suc = X . Y

-- | The (augmented) simplex category is the category of finite ordinals and order preserving maps.
instance CategoryOf Nat where
  type (~>) = Simplex
  type Ob a = IsNat a

instance Promonad Simplex where
  id @a = case singNat @a of
    SZ -> ZZ
    SS -> suc id
  ZZ . f = f
  Y f . g = Y (f . g)
  X f . Y g = f . g
  X f . X g = X (X f . g)

instance Profunctor Simplex where
  dimap = dimapDefault
  r \\ ZZ = r
  r \\ Y f = r \\ f
  r \\ X f = r \\ f

instance HasInitialObject Nat where
  type InitialObject = Z
  initiate @a = case singNat @a of
    SZ -> ZZ
    SS @a' -> Y (initiate @_ @a')

instance HasTerminalObject Nat where
  type TerminalObject = S Z
  terminate @a = case singNat @a of
    SZ -> Y ZZ
    SS @n -> X (terminate @_ @n)

data family Forget :: Nat +-> Type
instance FunctorForRep Forget where
  type Forget @ n = Fin n
  fmap ZZ = id
  fmap (Y f) = FS . fmap @Forget f
  fmap (X f) = \case
    FZ -> FZ
    FS n -> fmap @Forget f n

data family Pick :: Type -> OPPOSITE Nat +-> Type
instance FunctorForRep (Pick a) where
  type (Pick a) @ OP n = Vec n a
  fmap (Op ZZ) VNil = VNil
  fmap (Op (Y f)) (_ ::: xs) = fmap @(Pick a) (Op f) xs
  fmap (Op (X f)) (x ::: xs) = x ::: fmap @(Pick a) (Op f) (x ::: xs)

instance MonoidalProfunctor Simplex where
  one = ZZ
  ZZ ** g = g
  Y f ** g = Y (f ** g)
  X f ** g = X (f ** g)

-- | Addition as monoidal tensor.
instance Monoidal Nat where
  type Unit = Z
  type a ** b = a + b
  withOb2 @a @b r = case singNat @a of
    SZ -> r
    SS @a' -> withOb2 @_ @a' @b r
  associator @a @b @c = associatorDefault @a @b @c
  associatorInv @a @b @c = associatorDefault @a @b @c

-- Not symmetric monoidal

instance Monoid Z where
  mempty = ZZ
  mappend = ZZ

instance Monoid (S Z) where
  mempty = Y ZZ
  mappend = X (X (Y ZZ))

data family Replicate :: k -> Nat +-> k
instance (Monoid m) => FunctorForRep (Replicate m) where
  type Replicate m @ Z = Unit
  type Replicate m @ S b = m ** (Replicate m @ b)
  fmap ZZ = one
  fmap (Y f) = let g = fmap @(Replicate m) f in (mempty @m ** g) . leftUnitorInv \\ g
  fmap (X (Y f)) = obj @m ** fmap @(Replicate m) f
  fmap (X (X @x f)) =
    let g = fmap @(Replicate m) (X f)
        b = fmap @(Replicate m) (src f)
    in g . (mappend @m ** b) . associatorInv @_ @m @m @(Replicate m @ x) \\ b