packages feed

moonlight-category-0.1.0.0: src-public/Moonlight/Category/Notation.hs

-- | An opt-in ergonomic notation for working with 'FinCat' morphisms that reads as
-- mathematics while staying zero-cost. Every binding here is a trusted, total view
-- over already-validated data: because the 'FinMor' constructor is unexported, every
-- morphism in hand was produced by a checked path, so 'dom'/'cod' need not re-validate
-- and compile to plain record reads.
--
-- Construction of finite categories lives in "Moonlight.Category.Presentation".
-- This module begins only after a 'FinCat' has been compiled and validated.
--
-- This module is deliberately /not/ re-exported by "Moonlight.Category": the scoped
-- operators below are introduced only where you ask for them, leaving the rest of the
-- public facade operator-averse.
--
-- == Scoped operators
--
-- Composition and reachability need the category, so pin it once with a @let@ and the
-- mathematics reads on the page:
--
-- > import Moonlight.Category.Notation
-- >
-- > example category f g h =
-- >   let (∘) = composeIn category   -- g ∘ f  ≡  g after f
-- >       (≤) = reachableIn category
-- >    in (h ∘ g ∘ f, dom f, cod h, 0 ≤ (2 :: FinObjectId))
module Moonlight.Category.Notation
  ( dom,
    cod,
    domObj,
    codObj,
    idOf,
    hom,
    composeIn,
    reachableIn,
  )
where

import Data.Maybe (isJust)
import Moonlight.Category.Pure.Category (composeMor)
import Moonlight.Category.Pure.FinCat
  ( FinCat,
    FinCatError,
    FinMor,
    FinObj,
    FinObjectId,
    finCatHomMorphism,
    finObjectIdentityMor,
    finCatMorphismIdByEndpoints,
    finMorCodObject,
    finMorDomObject,
    finMorSourceId,
    finMorTargetId,
  )

-- | The source object identifier of a morphism. O(1), total.
dom :: FinMor -> FinObjectId
dom = finMorSourceId
{-# INLINE dom #-}

-- | The target object identifier of a morphism. O(1), total.
cod :: FinMor -> FinObjectId
cod = finMorTargetId
{-# INLINE cod #-}

-- | The source object of a morphism. O(1), total.
domObj :: FinMor -> FinObj
domObj = finMorDomObject
{-# INLINE domObj #-}

-- | The target object of a morphism. O(1), total.
codObj :: FinMor -> FinObj
codObj = finMorCodObject
{-# INLINE codObj #-}

-- | The identity morphism at an already validated object.
idOf :: FinObj -> FinMor
idOf = finObjectIdentityMor
{-# INLINE idOf #-}

-- | The unique morphism between two endpoints, when one exists.
hom :: FinCat -> FinObjectId -> FinObjectId -> Maybe FinMor
hom = finCatHomMorphism
{-# INLINE hom #-}

-- | Composition pinned to a category: @composeIn cat g f@ is @g ∘ f@ (f then g), and
-- is 'Left' exactly when the endpoints do not meet. Bind to @(∘)@ at the use site.
composeIn :: FinCat -> FinMor -> FinMor -> Either FinCatError FinMor
composeIn = composeMor
{-# INLINE composeIn #-}

-- | Whether the second object is reachable from the first (O(1) on the dense form).
-- Bind to @(≤)@ at the use site for a preorder reading.
reachableIn :: FinCat -> FinObjectId -> FinObjectId -> Bool
reachableIn category sourceId targetId =
  isJust (finCatMorphismIdByEndpoints category sourceId targetId)
{-# INLINE reachableIn #-}