gongju-0.1.0.0: src/Gongju/Kan.hs
{-# LANGUAGE AllowAmbiguousTypes #-}
{-# LANGUAGE ConstraintKinds #-}
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE PolyKinds #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeApplications #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE UndecidableInstances #-}
{-# LANGUAGE UndecidableSuperClasses #-}
-- | Module: Gongju.Kan
-- Description: Kan Extensions, Yoneda, and Codensity Fusion for Gongju
--
-- Integrates Right and Left Kan extensions ('t:Ran', 't:Lan'), Yoneda lemma embeddings
-- ('t:Yoneda', 't:Coyoneda'), and Codensity / Density monad-comonad generators
-- ('t:Codensity', 't:Density') from @kan-extensions@ into Gongju's open tape composition engine.
--
-- Enables:
-- * Structural Kan rewrites without typeclass constraints on @g@ or @h@.
-- * $O(1)$ functor mapping fusion via 't:Yoneda' and 't:Coyoneda'.
-- * $O(1)$ monad bind optimization via 't:Codensity' CPS transformations.
module Gongju.Kan
( -- * Re-exported Canonical Kan Types
Lan(..)
, Ran(..)
, toRan
, fromRan
, Yoneda(..)
, liftYoneda
, lowerYoneda
, Coyoneda(..)
, liftCoyoneda
, lowerCoyoneda
, Codensity(..)
, liftCodensity
, lowerCodensity
, Density(..)
, liftDensity
, lowerDensity
-- * Kan Structural Unit & Counit Operations
, ranCounit
, ranUnit
, lanUnit
, lanCounit
-- * Open Kan Tags
, PRanC
, PRanU
, PLanU
, PLanC
, PCoY
, PUnCoY
, PYon
, PUnYon
, PCodM
, PUnCod
, PDenW
, PUnDen
-- * Ergonomic Aliases
, RanC
, RanU
, LanU
, LanC
, CoY
, UnCoY
, Yon
, UnYon
, CodM
, UnCod
, DenW
, UnDen
) where
import Control.Comonad (Comonad, extend)
import Control.Comonad.Density
( Density (..)
, liftDensity
)
import Control.Monad.Codensity
( Codensity (..)
, lowerCodensity
)
import Data.Functor.Coyoneda
( Coyoneda (..)
, liftCoyoneda
, lowerCoyoneda
)
import Data.Functor.Kan.Lan
( Lan (..)
)
import Data.Functor.Kan.Ran
( Ran (..)
, fromRan
, toRan
)
import Data.Functor.Yoneda
( Yoneda (..)
, liftYoneda
, lowerYoneda
)
import Gongju.Composition
( F
, InOrder
, MapPath (..)
, StepPathMask (..)
, StepRole (..)
)
import Gongju.Peano (Append, Init)
import Gongju.Positional (ExpectArrow)
-- ---------------------------------------------------------------------------
-- 1. Kan Universal Unit & Counit Operations
-- ---------------------------------------------------------------------------
-- | Universal Counit of Ran: @Ran g h (g a) -> h a@ (zero constraints).
ranCounit :: Ran g h (g a) -> h a
ranCounit (Ran k) = k id
{-# INLINE ranCounit #-}
-- | Identity Unit of Ran: @a -> Ran g g a@ (zero constraints).
ranUnit :: a -> Ran g g a
ranUnit a = Ran ($ a)
{-# INLINE ranUnit #-}
-- | Universal Unit of Lan: @h a -> Lan g h (g a)@ (zero constraints).
lanUnit :: h a -> Lan g h (g a)
lanUnit ha = Lan id ha
{-# INLINE lanUnit #-}
-- | Identity Counit of Lan: @Lan g g a -> a@ (zero constraints).
lanCounit :: Lan g g a -> a
lanCounit (Lan f ga) = f ga
{-# INLINE lanCounit #-}
-- | Lift a monadic action into 't:Codensity' for CPS fusion.
liftCodensity :: Monad m => m a -> Codensity m a
liftCodensity m = Codensity (m >>=)
{-# INLINE liftCodensity #-}
-- | Lower 't:Density' back into the underlying comonad.
lowerDensity :: Comonad w => Density w a -> w a
lowerDensity (Density f wb) = extend f wb
{-# INLINE lowerDensity #-}
-- ---------------------------------------------------------------------------
-- 2. Open Mode Tags & Aliases
-- ---------------------------------------------------------------------------
-- | Tag for Ran Counit: collapses @Ran g h (g inner) -> h inner@.
data PRanC
-- | Tag for Ran Unit: expands @inner -> Ran g g inner@.
data PRanU
-- | Tag for Lan Unit: expands @h inner -> Lan g h (g inner)@.
data PLanU
-- | Tag for Lan Counit: collapses @Lan g g inner -> inner@.
data PLanC
-- | Tag for lifting arguments into 't:Coyoneda'.
data PCoY
-- | Tag for lowering 't:Coyoneda' via single 'fmap'.
data PUnCoY
-- | Tag for lifting arguments into 't:Yoneda'.
data PYon
-- | Tag for lowering 't:Yoneda' into the underlying functor.
data PUnYon
-- | Tag for lifting monadic arguments into 't:Codensity'.
data PCodM
-- | Tag for lowering 't:Codensity' back to the underlying monad.
data PUnCod
-- | Tag for lifting comonadic arguments into 't:Density'.
data PDenW
-- | Tag for lowering 't:Density' back to the underlying comonad.
data PUnDen
-- | In-order Ran Counit alias.
type RanC = InOrder PRanC
-- | In-order Ran Unit alias.
type RanU = InOrder PRanU
-- | In-order Lan Unit alias.
type LanU = InOrder PLanU
-- | In-order Lan Counit alias.
type LanC = InOrder PLanC
-- | In-order Coyoneda lifting alias.
type CoY = InOrder PCoY
-- | In-order Coyoneda lowering alias.
type UnCoY = InOrder PUnCoY
-- | In-order Yoneda lifting alias.
type Yon = InOrder PYon
-- | In-order Yoneda lowering alias.
type UnYon = InOrder PUnYon
-- | In-order Codensity lifting alias.
type CodM = InOrder PCodM
-- | In-order Codensity lowering alias.
type UnCod = InOrder PUnCod
-- | In-order Density lifting alias.
type DenW = InOrder PDenW
-- | In-order Density lowering alias.
type UnDen = InOrder PUnDen
-- ---------------------------------------------------------------------------
-- 3. StepRole Instances (Kan Extensions & Yoneda Fusion)
-- ---------------------------------------------------------------------------
-- | Ran Counit: collapses @Ran g h (g inner)@ to @h inner@ at the tip.
instance forall base active ms m t3 acc acc' out g h inner.
( MapPath (Init (Init active)) (Ran g h (g inner)) (h inner) acc acc'
, StepPathMask base (Init active) ms m t3 acc' out
) => StepRole PRanC base active ms m t3 acc out where
stepRole f acc =
stepPathMask @base @(Init active) @ms @m @t3 @acc' @out f
(mapPath @(Init (Init active)) @(Ran g h (g inner)) @(h inner) ranCounit acc)
{-# INLINE stepRole #-}
-- | Ran Unit: inserts @Ran g g@ around @inner@.
instance forall base active ms m t3 acc acc' out g inner.
( MapPath active inner (Ran g g inner) acc acc'
, StepPathMask base (Append active '[ F ]) ms m t3 acc' out
) => StepRole PRanU base active ms m t3 acc out where
stepRole f acc =
stepPathMask @base @(Append active '[ F ]) @ms @m @t3 @acc' @out f
(mapPath @active @inner @(Ran g g inner) ranUnit acc)
{-# INLINE stepRole #-}
-- | Lan Unit: expands @h inner@ to @Lan g h (g inner)@.
instance forall base active ms m t3 acc acc' out g h inner.
( MapPath (Init active) (h inner) (Lan g h (g inner)) acc acc'
, StepPathMask base (Append active '[ F ]) ms m t3 acc' out
) => StepRole PLanU base active ms m t3 acc out where
stepRole f acc =
stepPathMask @base @(Append active '[ F ]) @ms @m @t3 @acc' @out f
(mapPath @(Init active) @(h inner) @(Lan g h (g inner)) lanUnit acc)
{-# INLINE stepRole #-}
-- | Lan Counit: collapses @Lan g g inner@ to @inner@.
instance forall base active ms m t3 acc acc' out g inner.
( MapPath (Init active) (Lan g g inner) inner acc acc'
, StepPathMask base (Init active) ms m t3 acc' out
) => StepRole PLanC base active ms m t3 acc out where
stepRole f acc =
stepPathMask @base @(Init active) @ms @m @t3 @acc' @out f
(mapPath @(Init active) @(Lan g g inner) @inner lanCounit acc)
{-# INLINE stepRole #-}
-- | Coyoneda lifting: wraps argument in 't:Coyoneda' with zero constraints.
instance (ExpectArrow "StepRole PCoY" acc (Coyoneda φ a) rTail, fa ~ φ a, StepPathMask base '[] ms m t3 rTail out')
=> StepRole PCoY base '[] ms m t3 acc (fa -> out') where
stepRole f acc fa = stepPathMask @base @'[] @ms f (acc (liftCoyoneda fa))
{-# INLINE stepRole #-}
instance forall base l ls ms m t3 acc acc' out' φ a rTail fa.
( fa ~ φ a
, MapPath (l ': ls) (Coyoneda φ a -> rTail) rTail acc acc'
, StepPathMask base (l ': ls) ms m t3 acc' out'
) => StepRole PCoY base (l ': ls) ms m t3 acc (fa -> out') where
stepRole f acc fa =
stepPathMask @base @(l ': ls) @ms @m @t3 @acc' @out' f
(mapPath @(l ': ls) @(Coyoneda φ a -> rTail) @rTail (\g -> g (liftCoyoneda fa)) acc)
{-# INLINE stepRole #-}
-- | Coyoneda lowering: unrolls 't:Coyoneda' to underlying functor via single 'fmap'.
instance forall base active ms m t3 acc acc' out φ inner.
( Functor φ
, MapPath (Init active) (Coyoneda φ inner) (φ inner) acc acc'
, StepPathMask base active ms m t3 acc' out
) => StepRole PUnCoY base active ms m t3 acc out where
stepRole f acc =
stepPathMask @base @active @ms @m @t3 @acc' @out f
(mapPath @(Init active) @(Coyoneda φ inner) @(φ inner) lowerCoyoneda acc)
{-# INLINE stepRole #-}
-- | Yoneda lifting: wraps argument in 't:Yoneda' for $O(1)$ composition.
instance (Functor φ, ExpectArrow "StepRole PYon" acc (Yoneda φ a) rTail, fa ~ φ a, StepPathMask base '[] ms m t3 rTail out')
=> StepRole PYon base '[] ms m t3 acc (fa -> out') where
stepRole f acc fa = stepPathMask @base @'[] @ms f (acc (liftYoneda fa))
{-# INLINE stepRole #-}
instance forall base l ls ms m t3 acc acc' out' φ a rTail fa.
( Functor φ, fa ~ φ a
, MapPath (l ': ls) (Yoneda φ a -> rTail) rTail acc acc'
, StepPathMask base (l ': ls) ms m t3 acc' out'
) => StepRole PYon base (l ': ls) ms m t3 acc (fa -> out') where
stepRole f acc fa =
stepPathMask @base @(l ': ls) @ms @m @t3 @acc' @out' f
(mapPath @(l ': ls) @(Yoneda φ a -> rTail) @rTail (\g -> g (liftYoneda fa)) acc)
{-# INLINE stepRole #-}
-- | Yoneda lowering: extracts underlying functor from 't:Yoneda' (zero constraints).
instance forall base active ms m t3 acc acc' out φ inner.
( MapPath (Init active) (Yoneda φ inner) (φ inner) acc acc'
, StepPathMask base active ms m t3 acc' out
) => StepRole PUnYon base active ms m t3 acc out where
stepRole f acc =
stepPathMask @base @active @ms @m @t3 @acc' @out f
(mapPath @(Init active) @(Yoneda φ inner) @(φ inner) lowerYoneda acc)
{-# INLINE stepRole #-}
-- | Codensity lifting: lifts monadic argument into 't:Codensity' for CPS fusion.
instance (Monad m', ExpectArrow "StepRole PCodM" acc (Codensity m' a) rTail, ma ~ m' a, StepPathMask base '[] ms m t3 rTail out')
=> StepRole PCodM base '[] ms m t3 acc (ma -> out') where
stepRole f acc ma = stepPathMask @base @'[] @ms f (acc (liftCodensity ma))
{-# INLINE stepRole #-}
instance forall base l ls ms m t3 acc acc' out' m' a rTail ma.
( Monad m', ma ~ m' a
, MapPath (l ': ls) (Codensity m' a -> rTail) rTail acc acc'
, StepPathMask base (l ': ls) ms m t3 acc' out'
) => StepRole PCodM base (l ': ls) ms m t3 acc (ma -> out') where
stepRole f acc ma =
stepPathMask @base @(l ': ls) @ms @m @t3 @acc' @out' f
(mapPath @(l ': ls) @(Codensity m' a -> rTail) @rTail (\g -> g (liftCodensity ma)) acc)
{-# INLINE stepRole #-}
-- | Codensity lowering: runs 't:Codensity' back to underlying monad.
instance forall base active ms m t3 acc acc' out m' inner.
( Applicative m'
, MapPath (Init active) (Codensity m' inner) (m' inner) acc acc'
, StepPathMask base active ms m t3 acc' out
) => StepRole PUnCod base active ms m t3 acc out where
stepRole f acc =
stepPathMask @base @active @ms @m @t3 @acc' @out f
(mapPath @(Init active) @(Codensity m' inner) @(m' inner) lowerCodensity acc)
{-# INLINE stepRole #-}
-- | Density lifting: lifts comonadic argument into 't:Density'.
instance (Comonad w, ExpectArrow "StepRole PDenW" acc (Density w a) rTail, wa ~ w a, StepPathMask base '[] ms m t3 rTail out')
=> StepRole PDenW base '[] ms m t3 acc (wa -> out') where
stepRole f acc wa = stepPathMask @base @'[] @ms f (acc (liftDensity wa))
{-# INLINE stepRole #-}
instance forall base l ls ms m t3 acc acc' out' w a rTail wa.
( Comonad w, wa ~ w a
, MapPath (l ': ls) (Density w a -> rTail) rTail acc acc'
, StepPathMask base (l ': ls) ms m t3 acc' out'
) => StepRole PDenW base (l ': ls) ms m t3 acc (wa -> out') where
stepRole f acc wa =
stepPathMask @base @(l ': ls) @ms @m @t3 @acc' @out' f
(mapPath @(l ': ls) @(Density w a -> rTail) @rTail (\g -> g (liftDensity wa)) acc)
{-# INLINE stepRole #-}
-- | Density lowering: runs 't:Density' back to underlying comonad.
instance forall base active ms m t3 acc acc' out w inner.
( Comonad w
, MapPath (Init active) (Density w inner) (w inner) acc acc'
, StepPathMask base active ms m t3 acc' out
) => StepRole PUnDen base active ms m t3 acc out where
stepRole f acc =
stepPathMask @base @active @ms @m @t3 @acc' @out f
(mapPath @(Init active) @(Density w inner) @(w inner) lowerDensity acc)
{-# INLINE stepRole #-}