packages feed

yield-0.0.0.0: library/Control/Monad/Trans/Codensity.hs

{-# LANGUAGE UndecidableInstances #-}

module Control.Monad.Trans.Codensity
  ( CodensityT (..)
  ) where

import Control.Monad.IO.Class (MonadIO (..))
import Control.Monad.Reader (MonadReader (ask, local))
import Control.Monad.State (MonadState (state))
import Control.Monad.Trans.Class (MonadTrans (..))
import Control.Monad.Yield.Class (MonadYield (..))
import Data.Kind (Type)
import Prelude (Applicative (..), Functor (..), Monad (..), const, ($), (.))

-- | The "codensity transform", taken as an excerpt from the @kan-extensions@
--   package, following the model of @conduit@ to permit efficient monadic bind
newtype CodensityT (m :: Type -> Type) (a :: Type) = CodensityT {runCodensity :: forall b. (a -> m b) -> m b}

instance Functor (CodensityT m) where
  fmap f (CodensityT m) = CodensityT (\k -> m (k . f))

instance Applicative (CodensityT m) where
  pure x = CodensityT (\k -> k x)
  CodensityT f <*> CodensityT g = CodensityT (\bfr -> f (\ab -> g (bfr . ab)))

instance Monad (CodensityT m) where
  m >>= k = CodensityT (\c -> runCodensity m (\a -> runCodensity (k a) c))

instance MonadTrans CodensityT where
  lift m = CodensityT (m >>=)

instance MonadIO m => MonadIO (CodensityT m) where
  liftIO = lift . liftIO

instance MonadYield a m => MonadYield a (CodensityT m) where
  yield = lift . yield

instance MonadReader r m => MonadReader r (CodensityT m) where
  ask = CodensityT (ask >>=)
  local f m = CodensityT $ \c -> ask >>= \r -> local f . runCodensity m $ local (const r) . c

instance MonadState s m => MonadState s (CodensityT m) where
  state = lift . state