packages feed

proarrow-0.4.0.0: src/Proarrow/Tools/SMC/Internal/Frobenius.hs

{-# LANGUAGE AllowAmbiguousTypes #-}

-- | Internal module of "Proarrow.Tools.SMC": index notation for categories whose index types are
-- Frobenius algebras. It exports everything, also what the public module keeps hidden.
module Proarrow.Tools.SMC.Internal.Frobenius where

import GHC.TypeNats (type (+))

import Proarrow.Category.Monoidal (Monoidal (..), MonoidalProfunctor, rightUnitorInvWith)
import Proarrow.Category.Monoidal.Hypergraph (Frobenius, cap)
import Proarrow.Core (Profunctor (..), Promonad (..))
import Proarrow.Monoid (Monoid (..))
import Prelude (type (~))

import Proarrow.Tools.SMC.Internal.Context
import Proarrow.Tools.SMC.Internal.Pattern
import Proarrow.Tools.SMC.Internal.Syntax
import Proarrow.Tools.SMC.Internal.Term

infixl 7 *^
infixl 7 ^*

-- | An index summed over: the binder's variable is fed by the unit of its type's monoid, which,
-- copied to every use, is the sum over all the values the index can take. The body receives the
-- index through a pattern (see /Patterns/).
{-# INLINE sumOver #-}
sumOver
  :: forall {k} {p} (a :: SYN k) d r b t cont
   . (Profunctor p, Frobenius (Interp a), Binds p d r a b t cont)
  => (t -> cont)
  -> TermP p d r b
sumOver k =
  withCtxOb @r
    ( withSynOb @a
        ( MkTerm
            (lmap (rightUnitorInvWith @(Interp (Mul r)) (mempty @(Interp a))) (bound @p @d @r @a @b k))
        )
    )

-- | An index summed over, as 'sumOver', for a body that refers to the index as the variable of id
-- @d@ instead of through a pattern.
{-# INLINE sumVar #-}
sumVar
  :: forall {k} {p} (a :: SYN k) d g' g b
   . (Profunctor p, Frobenius (Interp a), KnownObj a, BindVar d a g' g)
  => TermP p (d + 1) g' b
  -> TermP p d g b
sumVar (MkTerm body) =
  withCtxOb @g
    ( withSynOb @a
        (MkTerm (lmap (bindVar @d @a @g' @g . rightUnitorInvWith @(Interp (Mul g)) (mempty @(Interp a))) body))
    )

-- | The Kronecker delta: the scalar that says two wires of an index type carry the same value. It
-- is the cap of the Frobenius algebra, @'Proarrow.Monoid.counit' . 'Proarrow.Monoid.mappend'@.
{-# INLINE delta #-}
delta
  :: forall {k} {p} (a :: SYN k) d g1 g2
   . (MonoidalProfunctor p, Frobenius (Interp a), KnownObj a, Merge g1 g2)
  => TermP p d g1 a -> TermP p d g2 a -> TermP p d (Union g1 g2) I
delta x y = rmapT (cap @(Interp a)) (x ** y)

-- | A term multiplied by a scalar on its left. The scalar's type interprets to 'Unit',
-- including both 'I' and @'F' Unit@. At 'I' it is the product of two scalars.
{-# INLINE (*^) #-}
(*^)
  :: forall {k} {p} d g1 g2 (a :: SYN k) s
   . (MonoidalProfunctor p, KnownObj a, Merge g1 g2, Interp s ~ Unit)
  => TermP p d g1 s -> TermP p d g2 a -> TermP p d (Union g1 g2) a
s *^ x = withSynOb @a (rmapT (leftUnitor @k @(Interp a)) (s ** x))

-- | A term multiplied by a scalar on its right.
{-# INLINE (^*) #-}
(^*)
  :: forall {k} {p} d g1 g2 (a :: SYN k) s
   . (MonoidalProfunctor p, KnownObj a, Merge g1 g2, Interp s ~ Unit)
  => TermP p d g1 a -> TermP p d g2 s -> TermP p d (Union g1 g2) a
x ^* s = withSynOb @a (rmapT (rightUnitor @k @(Interp a)) (x ** s))