{-| This module provides the 'IFunctor' and 'IMonad' classes which are the indexed counterparts to 'Functor' and 'Monad' from @Control.Monad@. -} {-# LANGUAGE Rank2Types, TypeOperators #-} module Control.IMonad.Core ( -- * Indexed Monads -- $imonads IFunctor(..), IMonad(..), -- * Functions -- $functions (?>=), (=?>), (>>)) import Control.Category.Index infixr 1 =?> infixl 1 ?>= {- $imonads I deviate from Conor's terminology, referring to his monads on indexed types as \"indexed monads\" and referring to his indexed monads as \"restricted monads\". This module provides \"indexed monads\". Indexed monads generalize the traditional approach to parametrizing the initial and final states of ordinary monads. The 'IMonad' class does not require specifying a concrete index of kind @*@ for the intermediate or final state of the 'bindI' operation, permitting operations which may end in multiple possible states. -} {-| An endofunctor within the category of index-preserving functions All instances must satisfy the functor laws: > fmapI id == id > > fmapI (f . g) == fmapI f . fmapI g -} class IFunctor f where fmapI :: (a :-> b) -> (f a :-> f b) {-| An indexed monad All instances must satisfy the monad laws: > returnI >?> f = f > > f >?> returnI = f > > (f >?> g) >?> h = f >?> (g >?> h) -} class (IFunctor m) => IMonad m where returnI :: a :-> m a bindI :: (a :-> m b) -> (m a :-> m b) {- $functions Functions derived from 'returnI' and 'bindI' -} -- | An infix 'bindI' (= (a :-> m b) -> (m a :-> m b) (==) :: (IMonad m) => m a i -> (a :-> m b) -> m b i (?>=) = flip bindI {-| Composition of indexed Kleisli arrows This is equivalent to ('>>>') from @Control.Category@. -} (>?>) :: (IMonad m) => (a :-> m b) -> (b :-> m c) -> (a :-> m c) f >?> g = \x -> f x ?>= g {-| Composition of indexed Kleisli arrows This is equivalent to ('<<<') from @Control.Category@. -} ( (b :-> m c) -> (a :-> m b) -> (a :-> m c) f f =