proarrow-0.1.0.0: src/Proarrow/Profunctor/Instance/Star.hs
{-# LANGUAGE AllowAmbiguousTypes #-}
-- | 'Star' embeds a functor @f@ as a profunctor with the functor on the target side:
-- @Star f a b = a ~> f b@. It is the representable profunctor of @f@; for a Haskell monad @m@,
-- @Star (Prelude m)@ is its Kleisli promonad.
module Proarrow.Profunctor.Instance.Star where
import Control.Monad qualified as P
import Data.Functor.Compose (Compose (..))
import Data.Kind (Type)
import Prelude qualified as P
import Proarrow.Category.Enriched.Thin (DecidableProfunctor (..), Thin, ThinProfunctor (..), mapDecision)
import Proarrow.Category.Instance.Nat (ApplyAction, Nat' (..), type (.->) (..))
import Proarrow.Category.Instance.Prof (Prof (..))
import Proarrow.Category.Monoidal (Monoidal (..), MonoidalProfunctor (..), Tensor)
import Proarrow.Category.Monoidal.Action (CoprodAction, ProdAction, SubAction)
import Proarrow.Category.Monoidal.Applicative (Alternative (..), Applicative (..))
import Proarrow.Category.Monoidal.Distributive (Distributive, Traversable (..), baseTraverse)
import Proarrow.Category.Monoidal.Strength (Strong (..))
import Proarrow.Colimit.BinaryCoproduct (COPROD (..), Coprod (..), HasBinaryCoproducts (..), HasCoproducts, (++))
import Proarrow.Colimit.Initial (initiate)
import Proarrow.Core (CategoryOf (..), Hom, Profunctor (..), Promonad (..), lmap, obj, (:~>), type (+->))
import Proarrow.Functor (Functor (..), Prelude (..), withObF)
import Proarrow.Profunctor.Instance.Composition ((:.:) (..))
import Proarrow.Profunctor.Instance.Coproduct ((:+:) (..))
import Proarrow.Profunctor.Representable (Representable (..), dimapRep)
type Star' :: j .-> k -> j +-> k
data Star' f a b where
Star' :: (Ob b) => {unStar :: a ~> f b} -> Star' (NT f) a b
type Star f = Star' (NT f)
pattern Star :: () => (Ob b) => (a ~> f b) -> Star f a b
pattern Star f = Star' f
{-# COMPLETE Star #-}
instance (Functor f) => Profunctor (Star f) where
dimap = dimapRep
r \\ Star f = r \\ f
instance (CategoryOf j, CategoryOf k) => Functor (Star' :: (j .-> k) -> j +-> k) where
map (Nat' n) = Prof \(Star f) -> Star (n . f)
instance (Functor f) => Representable (Star f) where
type Star f % a = f a
index = unStar
tabulate = Star
repMap = map
instance (Profunctor p) => Promonad (Star ((:+:) p)) where
id = Star (Prof InjR)
Star (Prof l) . Star (Prof r) = Star (Prof (\a -> case r a of InjL p -> InjL p; InjR b -> l b))
instance (P.Monad m) => Promonad (Star (Prelude m)) where
id = Star (Prelude . P.pure)
Star g . Star f = Star \a -> Prelude (unPrelude (f a) P.>>= (unPrelude . g))
composeStar :: (Functor f) => Star f :.: Star g :~> Star (Compose f g)
composeStar (Star f :.: Star g) = Star (Compose . map g . f)
instance (Applicative f, Monoidal j, Monoidal k) => MonoidalProfunctor (Star (f :: j -> k)) where
one = Star (pure id)
Star @a f ** Star @b g = withOb2 @_ @a @b (Star (liftA2 @f @a @b id . (f ** g)))
instance (Functor f, HasCoproducts j, HasCoproducts k) => MonoidalProfunctor (Coprod (Star (f :: j -> k))) where
one = Coprod (Star initiate)
Coprod (Star @a f) ** Coprod (Star @b g) = withObCoprod @_ @a @b (Coprod (Star (map (lft @_ @a @b) . f ||| map (rgt @_ @a @b) . g)))
-- Hmm, another wrapper required...
-- | Wraps the domain of @p@ in 'COPROD', letting 'Star' of an 'Alternative' functor be monoidal
-- over coproducts.
type CoprodDom :: j +-> k -> COPROD j +-> k
data CoprodDom p a b where
Co :: {unCo :: p a b} -> CoprodDom p a (COPR b)
instance (Profunctor p) => Profunctor (CoprodDom p) where
dimap l (Coprod r) (Co p) = Co (dimap l r p)
r \\ Co p = r \\ p
instance (Alternative f, Monoidal k, Distributive j) => MonoidalProfunctor (CoprodDom (Star (f :: j -> k))) where
one = Co (Star empty)
Co (Star @a f) ** Co (Star @b g) = let ab = obj @a +++ obj @b in Co (Star (alt @f @a @b ab . (f ** g))) \\ ab
instance (P.Functor f) => Strong ProdAction (Star (Prelude f)) where
act (Star k) = Star (\(a, x) -> P.fmap (a,) (k x))
instance (Functor f) => Strong Tensor (Star (f :: Type -> Type)) where
act (Star k) = Star (\(a, x) -> map (a,) (k x))
instance (Applicative f) => Strong CoprodAction (Star (f :: Type -> Type)) where
act (Star k) = Star (f ||| map P.Right . k)
where
f a = pure (\() -> P.Left a) ()
instance (P.Applicative f) => Strong (SubAction P.Traversable ApplyAction) (Star (Prelude f)) where
act (Star f) = Star (P.traverse f)
instance Traversable (Star P.Maybe) where
traverse (Star a2mb :.: p) = lmap a2mb go :.: Star id
where
go =
dimap
(P.maybe (P.Left ()) P.Right)
(P.const P.Nothing ||| P.Just)
(one ++ p)
instance Traversable (Star []) where
traverse (Star a2bs :.: p) = lmap a2bs go :.: Star id
where
go =
dimap
(\case [] -> P.Left (); (x : xs) -> P.Right (x, xs))
(P.const [] ||| P.uncurry (:))
(one ++ (p ** go))
-- | The list monad without the 'Prelude' wrapper, so that a Kleisli arrow of @[]@ reads as the
-- plain @a -> [b]@.
instance Promonad (Star []) where
id = Star P.return
Star l . Star r = Star (l P.<=< r)
starTraverse
:: forall t f a b
. ( Applicative (f :: Type -> Type)
, Functor t
, Traversable (Star t)
, Ob b
)
=> (a ~> f b) -> t a ~> f (t b)
starTraverse = baseTraverse @(Star t) @(Star f)
instance (Functor f, Thin k) => ThinProfunctor (Star f :: j +-> k) where
type HasArrow (Star f :: j +-> k) a b = HasArrow (Hom k) a (f b)
arr = Star arr
withArr (Star f) r = withArr f r
instance (Functor f, DecidableProfunctor (Hom k)) => DecidableProfunctor (Star f :: j +-> k) where
type Holds (Star f :: j +-> k) a b = Holds (Hom k) a (f b)
decide @a @b = withObF @f @b (mapDecision Star (decide @(Hom k) @a @(f b)))
toHolds (Star f) r = toHolds f r