packages feed

moonlight-category-0.1.0.0: src-abstract/Moonlight/Category/Pure/Poset.hs

{-# LANGUAGE DerivingStrategies #-}

-- | Posets viewed as thin categories: a morphism exists exactly where the
-- order relation holds.
module Moonlight.Category.Pure.Poset
  ( PosetCat (..),
    PosetOb (..),
    PosetMor,
    PosetTwoMor (..),
    PosetCompositor (..),
    mkPosetMor,
    posetSource,
    posetTarget,
    OrdinalLower (..),
    OrdinalUpper (..),
    LowerPosetCat,
    UpperPosetCat,
    LowerMor,
    UpperMor,
    mkLowerMor,
    mkUpperMor,
  )
where

import Data.Kind (Type)
import Moonlight.Category.Pure.Category (Category (..))
import Moonlight.Category.Pure.Galois (GaloisConnection (..), OrdinalGalois (..))
import Moonlight.Category.Pure.Thin
  ( ThinMorphism,
    identityThinMorphism,
    mkThinMorphismBy,
    thinMorphismSource,
    thinMorphismTarget,
  )

type PosetCat :: Type -> Type
-- | The thin category induced by an ordered carrier.
data PosetCat a = PosetCat
  deriving stock (Eq, Show)

type PosetOb :: Type -> Type
-- | An object in a poset category.
newtype PosetOb a = PosetOb {unPosetOb :: a}
  deriving stock (Eq, Ord, Show)

type PosetMor :: Type -> Type
-- | Order evidence from a source value to a target value.
data PosetMor a = PosetMor a a
  deriving stock (Eq, Show)

type PosetTwoMor :: Type -> Type
-- | The unique 2-morphism witness in a poset category.
data PosetTwoMor (a :: Type) = PosetTwoMor
  deriving stock (Eq, Show)

type PosetCompositor :: Type -> Type
-- | Composition evidence for poset morphisms.
data PosetCompositor (a :: Type) = PosetCompositor
  deriving stock (Eq, Show)

-- | Admit a poset morphism exactly when the source is below the target.
mkPosetMor :: Ord a => a -> a -> Maybe (PosetMor a)
mkPosetMor sourceValue targetValue =
  fromThinMorphism <$> mkThinMorphismBy (<=) sourceValue targetValue

-- | Project the source value.
posetSource :: PosetMor a -> a
posetSource (PosetMor sourceValue _) = sourceValue

-- | Project the target value.
posetTarget :: PosetMor a -> a
posetTarget (PosetMor _ targetValue) = targetValue

instance Ord a => Category (PosetCat a) where
  type Ob (PosetCat a) = PosetOb a
  type Mor (PosetCat a) = PosetMor a
  type TwoMor (PosetCat a) = PosetTwoMor a
  type Compositor (PosetCat a) = PosetCompositor a

  identity _ (PosetOb objectValue) =
    Right (fromThinMorphism (identityThinMorphism objectValue))

  compose _ leftMorphism rightMorphism
    | posetTarget rightMorphism /= posetSource leftMorphism = Left ()
    | otherwise =
        case mkPosetMor (posetSource rightMorphism) (posetTarget leftMorphism) of
          Just composedMorphism -> Right (composedMorphism, PosetCompositor)
          Nothing -> Left ()

  source _ = Right . PosetOb . posetSource
  target _ = Right . PosetOb . posetTarget

type OrdinalLower :: Type
-- | The lower carrier of the example ordinal Galois connection.
newtype OrdinalLower = OrdinalLower {unOrdinalLower :: Int}
  deriving stock (Eq, Ord, Show)

type OrdinalUpper :: Type
-- | The upper carrier of the example ordinal Galois connection.
newtype OrdinalUpper = OrdinalUpper {unOrdinalUpper :: Int}
  deriving stock (Eq, Ord, Show)

instance GaloisConnection OrdinalLower OrdinalUpper where
  alpha (OrdinalLower value) = OrdinalUpper (value * 2)
  gamma (OrdinalUpper value) = OrdinalLower (value `div` 2)

instance OrdinalGalois OrdinalLower OrdinalUpper where
  thresholds = map (\value -> (OrdinalLower value, OrdinalUpper (value * 2))) [0 .. 32]

type LowerPosetCat :: Type
-- | The poset category over t'OrdinalLower'.
type LowerPosetCat = PosetCat OrdinalLower

type UpperPosetCat :: Type
-- | The poset category over t'OrdinalUpper'.
type UpperPosetCat = PosetCat OrdinalUpper

type LowerMor :: Type
-- | A morphism in 'LowerPosetCat'.
type LowerMor = PosetMor OrdinalLower

type UpperMor :: Type
-- | A morphism in 'UpperPosetCat'.
type UpperMor = PosetMor OrdinalUpper

-- | Construct a lower-carrier order witness.
mkLowerMor :: OrdinalLower -> OrdinalLower -> Maybe LowerMor
mkLowerMor = mkPosetMor

-- | Construct an upper-carrier order witness.
mkUpperMor :: OrdinalUpper -> OrdinalUpper -> Maybe UpperMor
mkUpperMor = mkPosetMor


fromThinMorphism :: ThinMorphism a -> PosetMor a
fromThinMorphism thinMorphism =
  PosetMor
    (thinMorphismSource thinMorphism)
    (thinMorphismTarget thinMorphism)