proarrow-0.1.0.0: src/Proarrow/Category/Instance/Nat.hs
{-# OPTIONS_GHC -Wno-orphans #-}
-- | Functor categories: 'Nat' is the type of natural transformations between functors @j -> k@,
-- and the kind @j -> 'Data.Kind.Type'@ carries the category of 'Functor's with 'Nat' as its
-- morphisms and pointwise (co)limits. On @'Data.Kind.Type' -> 'Data.Kind.Type'@, functor
-- composition additionally gives a (closed) monoidal structure, the home of monads as monoids.
module Proarrow.Category.Instance.Nat where
import Data.Bifunctor qualified as P
import Data.Functor.Compose (Compose (..))
import Data.Functor.Const (Const (..))
import Data.Functor.Identity (Identity (..))
import Data.Functor.Product (Product (..))
import Data.Functor.Sum (Sum (..))
import Data.Kind (Type)
import Data.Void (Void, absurd)
import Prelude qualified as P
import Proarrow.Category.Instance.Product ((:**:) (..))
import Proarrow.Category.Instance.Prof (Prof (..))
import Proarrow.Category.Monoidal (Monoidal (..), MonoidalProfunctor (..))
import Proarrow.Category.Monoidal.Action (MonoidalAction (..))
import Proarrow.Category.Monoidal.Closed (Closed (..))
import Proarrow.Category.Monoidal.Coclosed (Coclosed (..))
import Proarrow.Colimit.BinaryCoproduct (HasBinaryCoproducts (..))
import Proarrow.Colimit.Copower (Copowered (..))
import Proarrow.Colimit.Initial (HasInitialObject (..))
import Proarrow.Core (CAT, CategoryOf (..), Is, Profunctor (..), Promonad (..), UN, dimapDefault, (//), type (+->))
import Proarrow.Functor (Functor (..), FunctorForRep (..), type (.~>))
import Proarrow.Limit.BinaryProduct (HasBinaryProducts (..), PROD (..), Prod (..))
import Proarrow.Limit.Power (Powered (..))
import Proarrow.Limit.Terminal (HasTerminalObject (..))
import Proarrow.Monoid (Comonoid (..))
import Proarrow.Profunctor.Instance.Composition ((:.:) (..))
import Proarrow.Profunctor.Representable (Rep)
type Nat :: CAT (j -> k)
data Nat f g where
Nat
:: (Functor f, Functor g)
=> {unNat :: f .~> g}
-> Nat f g
(!) :: Nat f g -> a ~> b -> f a ~> g b
Nat f ! ab = f . map ab \\ ab
-- | The category of functors with target category Hask.
instance CategoryOf (k1 -> Type) where
type (~>) = Nat
type Ob f = Functor f
instance Promonad (Nat :: CAT (j -> Type)) where
id @f = Nat (map @f id)
Nat f . Nat g = Nat (f . g)
instance Profunctor (Nat :: CAT (k1 -> Type)) where
dimap = dimapDefault
r \\ Nat{} = r
instance Functor (:.:) where
map (Prof n) = Nat (Prof \(p :.: q) -> n p :.: q)
instance (CategoryOf k1) => HasTerminalObject (k1 -> Type) where
type TerminalObject = Const ()
terminate = Nat \_ -> Const ()
instance (CategoryOf k1) => HasInitialObject (k1 -> Type) where
type InitialObject = Const Void
initiate = Nat \(Const v) -> absurd v
instance (Functor f, Functor g) => Functor (Product f g) where
map f (Pair x y) = Pair (map f x) (map f y)
instance HasBinaryProducts (k1 -> Type) where
type f && g = Product f g
withObProd r = r
fst = Nat \(Pair f _) -> f
snd = Nat \(Pair _ g) -> g
Nat f &&& Nat g = Nat \a -> Pair (f a) (g a)
instance (Functor f, Functor g) => Functor (Sum f g) where
map f (InL x) = InL (map f x)
map f (InR y) = InR (map f y)
instance HasBinaryCoproducts (k1 -> Type) where
type f || g = Sum f g
withObCoprod r = r
lft = Nat InL
rgt = Nat InR
Nat f ||| Nat g = Nat \case
InL x -> f x
InR y -> g y
data (f :~>: g) a where
Exp :: (Ob a) => (forall b. a ~> b -> f b -> g b) -> (f :~>: g) a
instance (Functor f, Functor g) => Functor (f :~>: g) where
map ab (Exp k) = ab // Exp \bc fc -> k (bc . ab) fc
instance (CategoryOf k1) => Closed (PROD (k1 -> Type)) where
type f ~~> g = PR (UN PR f :~>: UN PR g)
withObExp r = r
curry (Prod (Nat n)) = Prod (Nat \f -> Exp \ab g -> n (Pair (map ab f) g) \\ ab)
apply = Prod (Nat \(Pair (Exp k) g) -> k id g)
Prod (Nat m) ^^^ Prod (Nat n) = Prod (Nat \(Exp k) -> Exp \cd h -> m (k cd (n h)) \\ cd)
instance MonoidalProfunctor (Nat :: CAT (Type -> Type)) where
one = id
Nat n ** Nat m = Nat (\(Compose fg) -> Compose (n (map m fg)))
-- | Composition as monoidal tensor.
instance Monoidal (Type -> Type) where
type Unit = Identity
type f ** g = Compose f g
withOb2 r = r
leftUnitor = Nat (runIdentity . getCompose)
leftUnitorInv = Nat (Compose . Identity)
rightUnitor = Nat (map runIdentity . getCompose)
rightUnitorInv = Nat (Compose . map Identity)
associator = Nat (Compose . map Compose . getCompose . getCompose)
associatorInv = Nat (Compose . Compose . map getCompose . getCompose)
type ApplyAction = Rep ApplyAction'
data family ApplyAction' :: (Type -> Type, Type) +-> Type
instance FunctorForRep ApplyAction' where
type ApplyAction' @ '(f, x) = f x
fmap (n :**: f) = n ! f
instance MonoidalAction ApplyAction where
unitor = runIdentity
unitorInv = Identity
multiplicator = getCompose
multiplicatorInv = Compose
type Ran :: (j -> k) -> (j -> Type) -> k -> Type
newtype Ran j h a = Ran {runRan :: forall b. (a ~> j b) -> h b}
instance (CategoryOf k) => Functor (Ran j h :: k -> Type) where
map f (Ran k) = Ran \j -> k (j . f)
instance Closed (Type -> Type) where
type j ~~> h = Ran j h
withObExp r = r
curry (Nat n) = Nat \fa -> Ran \ajb -> n (Compose (map ajb fa))
apply = Nat \(Compose fja) -> runRan fja id
(^^^) (Nat by) (Nat xa) = Nat \h -> Ran \x -> by (runRan h (xa . x))
type Lan :: (j -> k) -> (j -> Type) -> k -> Type
data Lan j f a where
Lan :: (j b ~> a) -> f b -> Lan j f a
instance (CategoryOf k) => Functor (Lan j f :: k -> Type) where
map g (Lan k f) = Lan (g . k) f
instance Coclosed (Type -> Type) where
type f <~~ j = Lan j f
withObCoExp r = r
coeval = Nat (Compose . Lan id)
coevalUniv (Nat n) = Nat \(Lan k f) -> map k (getCompose (n f))
data (f :^: n) a where
Power :: (Ob a) => {unPower :: n -> f a} -> (f :^: n) a
instance (Functor f) => Functor (f :^: n) where
map g (Power k) = g // Power \n -> map g (k n)
instance Powered Type (k -> Type) where
type f ^ n = f :^: n
withObPower r = r
power f = Nat \g -> Power \n -> unNat (f n) g
unpower (Nat f) n = Nat \g -> unPower (f g) n
data (n :*.: f) a where
Copower :: (Ob a) => {unCopower :: (n, f a)} -> (n :*.: f) a
instance (Functor f) => Functor (n :*.: f) where
map g (Copower (n, f)) = g // Copower (n, map g f)
instance Copowered Type (k -> Type) where
type n *. f = n :*.: f
withObCopower r = r
copower f = Nat \(Copower (n, g)) -> unNat (f n) g
uncopower (Nat f) n = Nat \p -> f (Copower (n, p))
data CatAsComonoid k a where
CatAsComonoid :: forall {k} (c :: k) a. (Ob c) => (forall c'. c ~> c' -> a) -> CatAsComonoid k a
instance Functor (CatAsComonoid k) where
map f (CatAsComonoid k) = CatAsComonoid (f . k)
instance (CategoryOf k) => Comonoid (CatAsComonoid k) where
counit = Nat \(CatAsComonoid k) -> Identity (k id)
comult = Nat \(CatAsComonoid @a k) ->
Compose
( CatAsComonoid @a
\(f :: a ~> b) ->
f // CatAsComonoid @b
\g -> k (g . f)
)
-- | The coKleisli category of a comonoid @w@ in the functor category: an arrow from @a@ to @b@
-- is a map @w a -> b@.
data ComonoidAsCat (w :: Type -> Type) a b where
ComonoidAsCat :: (w a -> b) -> ComonoidAsCat w a b
instance (Functor w) => Profunctor (ComonoidAsCat w) where
dimap f g (ComonoidAsCat h) = ComonoidAsCat (g . h . map f)
instance (Comonoid w) => Promonad (ComonoidAsCat w) where
id = ComonoidAsCat (runIdentity . unNat counit)
ComonoidAsCat f . ComonoidAsCat g = ComonoidAsCat (f . map g . getCompose . unNat comult)
-- | The category of functors with target category @k2 -> k3 -> Type@.
-- @CategoryOf (k1 -> k2 -> Type)@ is reserved for profunctors.
instance CategoryOf (k1 -> k2 -> k3 -> Type) where
type (~>) = Nat
type Ob f = Functor f
instance Promonad (Nat :: CAT (k1 -> k2 -> k3 -> Type)) where
id @f = Nat (map @f id)
Nat f . Nat g = Nat (f . g)
instance Profunctor (Nat :: CAT (k1 -> k2 -> k3 -> Type)) where
dimap f g h = g . h . f
r \\ Nat{} = r
-- | The category of functors with target category k2 -> k3 -> k4 -> Type.
instance CategoryOf (k1 -> k2 -> k3 -> k4 -> Type) where
type (~>) = Nat
type Ob f = Functor f
instance Promonad (Nat :: CAT (k1 -> k2 -> k3 -> k4 -> Type)) where
id @f = Nat (map @f id)
Nat f . Nat g = Nat (f . g)
instance Profunctor (Nat :: CAT (k1 -> k2 -> k3 -> k4 -> Type)) where
dimap f g h = g . h . f
r \\ Nat{} = r
newtype j .-> k = NT (j -> k)
data Nat' f g where
Nat'
:: (Functor f, Functor g)
=> {unNat' :: f .~> g}
-> Nat' (NT f) (NT g)
-- | The category of functors and natural transformations.
instance CategoryOf (j .-> k) where
type (~>) = Nat'
type Ob f = (Is NT f, Functor (UN NT f))
instance Promonad (Nat' :: CAT (j .-> k)) where
id @(NT f) = Nat' (map @f id)
Nat' f . Nat' g = Nat' (f . g)
instance Profunctor (Nat' :: CAT (j .-> k)) where
dimap = dimapDefault
r \\ Nat'{} = r
instance Functor P.Either where map f = Nat (P.first f)
instance Functor (,) where map f = Nat (P.first f)
first :: (Functor (f :: i -> j -> k), (~>) P.~ (Nat :: CAT (j -> k)), Ob c) => (a ~> b) -> f a c ~> f b c
first f = unNat (map f)
bimap
:: (Functor (f :: i -> j -> k), (~>) P.~ (Nat :: CAT (j -> k)), Functor (f a))
=> a ~> c -> b ~> d -> f a b ~> f c d
bimap l r = first l . map r \\ r