packages feed

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

{-# LANGUAGE AllowAmbiguousTypes #-}

-- | Internal module of "Proarrow.Tools.SMC": functions and traces. It exports everything, also what
-- the public module keeps hidden.
module Proarrow.Tools.SMC.Internal.Closed where

import Data.Kind (Constraint, Type)
import Prelude (type (~))

import Proarrow.Category.Monoidal qualified as M
import Proarrow.Category.Monoidal.Closed (Closed (..))
import Proarrow.Category.Monoidal.Strength (Costrong, trace)
import Proarrow.Core (CAT, CategoryOf (..), Profunctor (..))

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 8 !

-- | A function: the body receives the argument through a pattern (see /Patterns/). This needs the
-- category to be closed.
{-# INLINE lam #-}
lam
  :: forall {k} d r (a :: SYN k) b t cont
   . (Closed k, Binds (~>) d r a b t cont)
  => (t -> cont)
  -> Term d r (a :-> b)
lam k = withCtxOb @r (withSynOb @a (MkTerm (curry @k @(Interp (Mul r)) @(Interp a) (bound @(~>) @d @r @a @b k))))

-- | Trace: the body receives the value fed back through a pattern (see /Patterns/), and returns
-- it again next to the result. This needs the category to be traced.
{-# INLINE loop #-}
loop
  :: forall {k} {p} (u :: SYN k) b d r t cont
   . (Costrong M.Tensor p, M.SymMonoidal k, KnownObj b, Binds p d r u (b :** u) t cont)
  => (t -> cont)
  -> TermP p d r b
loop k =
  withCtxOb @r
    ( withSynOb @u
        (withSynOb @b (MkTerm (trace @p @(Interp u) @(Interp (Mul r)) @(Interp b) (bound @p @d @r @u @(b :** u) k))))
    )

-- | Function application. A variable both the function and its argument use is copied.
-- Explicit exponentials determine their result syntax. Embedded function objects, such as
-- results of '(-<)', take their result syntax from the surrounding term.
type Apply :: forall {k}. CAT k -> Type -> Type -> Type -> Constraint
class Apply (p :: CAT k) f x r | f -> p where
  (!)
    :: (Closed k, M.MonoidalProfunctor p, KnownObj (TyOf @k x), KnownObj (TyOf @k r), Merge (CtxOf @k f) (CtxOf @k x))
    => f -> x -> r

instance (x ~ TermP p d g2 a, r ~ TermP p d (Union g1 g2) b) => Apply p (TermP p d g1 (a :-> b :: SYN k)) x r where
  {-# INLINE (!) #-}
  (!) = applyTerm @a @b

instance
  (f ~ (Interp a ~~> Interp b), x ~ TermP p d g2 a, r ~ TermP p d (Union g1 g2) b)
  => Apply p (TermP p d g1 (F f :: SYN k)) x r
  where
  {-# INLINE (!) #-}
  (!) = applyTerm @a @b

{-# INLINE applyTerm #-}
applyTerm
  :: forall {k} (a :: SYN k) b p d g1 g2 f
   . (Closed k, M.MonoidalProfunctor p, KnownObj a, KnownObj b, Merge g1 g2, Interp f ~ (Interp a ~~> Interp b))
  => TermP p d g1 f
  -> TermP p d g2 a
  -> TermP p d (Union g1 g2) b
applyTerm (MkTerm f) (MkTerm x) =
  withSynOb @a
    ( withSynOb @b
        (MkTerm (dimap (merge @g1 @g2) (apply @k @(Interp a) @(Interp b)) (f M.** x)))
    )