module Control.Categorical.Monad where import qualified Control.Monad as Base import Data.Function (($), flip) import Data.Functor.Identity import Data.List.NonEmpty (NonEmpty (..)) import qualified Data.List.NonEmpty as NE import Data.Semigroup (Arg (..)) import Control.Categorical.Functor infixr 1 >=>, <=<, =>=, =<= class Endofunctor s m => Monad s m where unit :: a `s` m a join :: m (m a) `s` m a join = bind id bind :: a `s` m b -> m a `s` m b bind f = join . map f (<=<) :: Monad s m => b `s` m c -> a `s` m b -> a `s` m c f <=< g = bind f . bind g . unit (>=>) :: Monad s m => a `s` m b -> b `s` m c -> a `s` m c (>=>) = flip (<=<) newtype Kleisli s m a b = Kleisli { kleisli :: a `s` m b } instance Monad s m => Category (Kleisli s m) where id = Kleisli unit Kleisli f . Kleisli g = Kleisli (f <=< g) instance {-# INCOHERENT #-} Base.Monad m => Monad (->) m where unit = Base.return join = Base.join bind = (Base.=<<) class Endofunctor s ɯ => Comonad s ɯ where counit :: ɯ a `s` a cut :: ɯ a `s` ɯ (ɯ a) cut = cobind id cobind :: ɯ a `s` b -> ɯ a `s` ɯ b cobind f = map f . cut (=<=) :: Comonad s ɯ => ɯ b `s` c -> ɯ a `s` b -> ɯ a `s` c f =<= g = counit . cobind f . cobind g (=>=) :: Comonad s ɯ => ɯ a `s` b -> ɯ b `s` c -> ɯ a `s` c (=>=) = flip (=<=) newtype Cokleisli s ɯ a b = Cokleisli { cokleisli :: ɯ a `s` b } instance Comonad s ɯ => Category (Cokleisli s ɯ) where id = Cokleisli counit Cokleisli f . Cokleisli g = Cokleisli (f =<= g) instance Comonad (->) Identity where counit = runIdentity cut = map Identity instance Comonad (->) NonEmpty where counit = NE.head cut (x:|xs) = (x:|xs) :| go xs where go [] = [] go (x:xs) = (x:|xs) : go xs instance Monoid m => Comonad (->) ((->) m) where counit = ($ mempty) cut f x y = f (x <> y) instance Comonad (->) ((,) a) where counit (_, b) = b cut (a, b) = (a, (a, b)) instance Comonad (->) (Arg a) where counit (Arg _ b) = b cut (Arg a b) = Arg a (Arg a b)