packages feed

proarrow-0.1.0.0: src/Proarrow/Promonad/Cont.hs

-- | The continuation promonad: @'Cont' r a b@ is a continuation transformer @(b '~>' r) -> (a '~>' r)@.
-- It is strong for the tensor but only premonoidal, as the order of effects matters.
module Proarrow.Promonad.Cont where

import Data.Kind (Type)
import Prelude (($))

import Proarrow.Category.Instance.Kleisli (KLEISLI (..), Kleisli (..))
import Proarrow.Category.Monoidal (MonoidalProfunctor (..), Tensor)
import Proarrow.Category.Monoidal.Closed (Closed (..), curry, uncurry)
import Proarrow.Category.Monoidal.StarAutonomous (ExpSA, StarAutonomous (..), applySA, currySA, expSA)
import Proarrow.Category.Monoidal.Strength (Strong (..))
import Proarrow.Colimit.BinaryCoproduct (Coprod (..), HasBinaryCoproducts (..), HasCoproducts)
import Proarrow.Core (CategoryOf (..), Profunctor (..), Promonad (..))
import Proarrow.Profunctor.Representable (Representable (..))

-- | An arrow from @a@ to @b@ is a mapping of continuations @(b '~>' r) -> (a '~>' r)@.
data Cont r a b where
  Cont :: (Ob a, Ob b) => {runCont :: (b ~> r) -> (a ~> r)} -> Cont r a b

instance (CategoryOf k) => Profunctor (Cont (r :: k)) where
  dimap l r (Cont f) = Cont ((. l) . f . (. r)) \\ l \\ r
  r \\ Cont{} = r
instance (CategoryOf k) => Promonad (Cont (r :: k)) where
  id = Cont id
  Cont f . Cont g = Cont (g . f)

-- | At @Type@ the continuation promonad is the continuation /monad/: @(b -> r) -> (a -> r)@ is
-- @a -> (b -> r) -> r@ by flipping the arguments, so @'Cont' r '%' b@ is the double-negation
-- @(b -> r) -> r@. This gives @'KLEISLI' ('Cont' r)@ its initial object and coproducts, which
-- hold for the Kleisli category of a monad but not of an arbitrary promonad.
instance Representable (Cont (r :: Type)) where
  type Cont r % b = (b -> r) -> r
  index (Cont f) a k = f k a
  tabulate g = Cont \k a -> g a k
  repMap f c k = c (k . f)

instance Strong Tensor (Cont (r :: Type)) where
  act (Cont yrxy) = Cont \byr -> uncurry (yrxy . curry byr)

-- Not costrong

-- | Only premonoidal not monoidal.
instance MonoidalProfunctor (Cont (r :: Type)) where
  one = Cont id
  Cont f ** Cont g = Cont \k (x1, y1) -> f (\x2 -> g (\y2 -> k (x2, y2)) y1) x1

instance (HasCoproducts k) => MonoidalProfunctor (Coprod (Cont (r :: k))) where
  one = Coprod (Cont id)
  Coprod (Cont @af @bf f) ** Coprod (Cont @ag @bg g) =
    withObCoprod @k @af @ag $
      withObCoprod @k @bf @bg $
        Coprod (Cont (\k -> f (k . lft @_ @bf @bg) ||| g (k . rgt @_ @bf @bg)))

instance StarAutonomous (KLEISLI (Cont (r :: Type))) where
  type Dual @(KLEISLI (Cont r)) (KL a) = KL (a ~~> r)
  withObDual r = r
  dual (Kleisli (Cont f)) = Kleisli (Cont \k br -> k (f br))
  dualInv (Kleisli (Cont f)) = Kleisli (Cont \k b -> f (\g -> g b) k)
  linDist (Kleisli (Cont f)) = Kleisli (Cont \k a -> k (\(b, c) -> f (\g -> g c) (a, b)))
  linDistInv (Kleisli (Cont f)) = Kleisli (Cont \k (a, b) -> k (\c -> f (\g -> g (b, c)) a))
instance Closed (KLEISLI (Cont (r :: Type))) where
  type a ~~> b = ExpSA a b
  withObExp r = r
  curry = currySA
  apply = applySA
  (^^^) = expSA

-- Not CompactClosed, needs ((a -> r, b -> r) -> r) -> ((a, b) -> r) -> r