pipes-2.2.0: Control/IMonad/Trans/Free.hs
-- | This module is the indexed version of "Control.Monad.Trans.Free"
{-# LANGUAGE KindSignatures, TypeOperators #-}
module Control.IMonad.Trans.Free (
-- * Free monad transformers
-- $freet
IFreeF(..),
IFreeT(..),
wrap,
liftF
) where
import Control.Category.Index
import Control.IMonad
import Control.IMonad.Trans
{- $freet
Indexed free monad transformers lift the constructor signatures to
the category of indexed Haskell functions: (':->').
> Return :: r :-> IFreeF f r x
> Wrap :: f x :-> IFreeF f r x
>
> IFreeT :: m (IFreeF f r (IFreeT f m r)) :-> IFreeT f m r
-}
-- | Indexed equivalent to @FreeF@
data IFreeF f r (x :: * -> *) i = Return (r i) | Wrap (f x i)
-- | Indexed equivalent to @FreeT@
newtype IFreeT f m r i = IFreeT { runIFreeT :: m (IFreeF f r (IFreeT f m r)) i }
instance (IFunctor f, IMonad m) => IFunctor (IFreeT f m) where
fmapI f x = x ?>= returnI . f
instance (IFunctor f, IMonad m) => IMonad (IFreeT f m) where
returnI = IFreeT . returnI . Return
bindI f m = IFreeT $
runIFreeT m ?>= \x ->
runIFreeT $ case x of
Return r -> f r
Wrap w -> wrap $ fmapI (bindI f) w
instance (IFunctor f) => IMonadTrans (IFreeT f) where
liftI = IFreeT . fmapI Return
-- | Indexed equivalent to @wrap@
wrap :: (IMonad m) => f (IFreeT f m r) :-> IFreeT f m r
wrap = IFreeT . returnI . Wrap
-- | Indexed equivalent to @liftF@
liftF :: (IFunctor f, IMonad m) => f r :-> IFreeT f m r
liftF x = wrap $ fmapI returnI x
-- FIXME: Add IIdentity so that IFree can be defined in terms of IFreeT