module Control.Monad.Codensity
( Codensity(..)
, lowerCodensity
, codensityToAdjunction
, adjunctionToCodensity
) where
import Control.Applicative
import Control.Monad.Reader.Class
import Control.Monad.State.Class
import Control.Monad.Free.Class
import Control.Monad (ap, MonadPlus(..))
import Data.Functor.Adjunction
import Data.Functor.Apply
import Control.Monad.Trans.Class
import Control.Monad.IO.Class
newtype Codensity m a = Codensity { runCodensity :: forall b. (a -> m b) -> m b }
instance Functor (Codensity k) where
fmap f (Codensity m) = Codensity (\k -> m (k . f))
instance Apply (Codensity f) where
(<.>) = ap
instance Applicative (Codensity f) where
pure x = Codensity (\k -> k x)
(<*>) = ap
instance Monad (Codensity f) where
return x = Codensity (\k -> k x)
m >>= k = Codensity (\c -> runCodensity m (\a -> runCodensity (k a) c))
instance MonadIO m => MonadIO (Codensity m) where
liftIO = lift . liftIO
instance MonadTrans Codensity where
lift m = Codensity (m >>=)
instance Alternative v => Alternative (Codensity v) where
empty = Codensity (\_ -> empty)
Codensity m <|> Codensity n = Codensity (\k -> m k <|> n k)
instance MonadPlus v => MonadPlus (Codensity v) where
mzero = Codensity (\_ -> mzero)
Codensity m `mplus` Codensity n = Codensity (\k -> m k `mplus` n k)
lowerCodensity :: Monad m => Codensity m a -> m a
lowerCodensity a = runCodensity a return
codensityToAdjunction :: Adjunction f g => Codensity g a -> g (f a)
codensityToAdjunction r = runCodensity r unit
adjunctionToCodensity :: Adjunction f g => g (f a) -> Codensity g a
adjunctionToCodensity f = Codensity (\a -> fmap (rightAdjunct a) f)
instance MonadFree f m => MonadFree f (Codensity m) where
wrap t = Codensity (\h -> wrap (fmap (\p -> runCodensity p h) t))
instance MonadReader r m => MonadState r (Codensity m) where
get = Codensity (ask >>=)
put s = Codensity (\k -> local (const s) (k ()))