monad-unlift-0.1.0.1: Control/Monad/Trans/Unlift.hs
{-# LANGUAGE ConstraintKinds #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE FunctionalDependencies #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeOperators #-}
{-# LANGUAGE UndecidableInstances #-}
-- | See overview in the README.md
module Control.Monad.Trans.Unlift
( -- * Trans
MonadTransUnlift
, Unlift (..)
, askUnlift
, askRun
-- * Base
, MonadBaseUnlift
, UnliftBase (..)
, askUnliftBase
, askRunBase
-- * Reexports
, MonadTrans (..)
, MonadBase (..)
, MonadTransControl (..)
, MonadBaseControl (..)
) where
import Control.Monad (liftM)
import Control.Monad.Base (MonadBase (..))
import Control.Monad.Trans.Class (MonadTrans (..))
import Control.Monad.Trans.Control (MonadBaseControl (..),
MonadTransControl (..))
import Data.Constraint ((:-), (\\))
import Data.Constraint.Forall (Forall, inst)
-- | A function which can move an action down the monad transformer stack, by
-- providing any necessary environment to the action.
--
-- Note that, if ImpredicativeTypes worked reliably, this type wouldn't be
-- necessary, and 'askUnlift' would simply include a more generalized type.
--
-- Since 0.1.0
newtype Unlift t = Unlift { unlift :: forall a n. Monad n => t n a -> n a }
class (StT t a ~ a) => Identical t a
instance (StT t a ~ a) => Identical t a
-- | A monad transformer which can be unlifted, obeying the monad morphism laws.
--
-- Since 0.1.0
class (MonadTransControl t, Forall (Identical t)) => MonadTransUnlift t
instance (MonadTransControl t, Forall (Identical t)) => MonadTransUnlift t
mkUnlift :: forall t m a . (Forall (Identical t), Monad m)
=> (forall n b. Monad n => t n b -> n (StT t b)) -> t m a -> m a
mkUnlift r act = r act \\ (inst :: Forall (Identical t) :- Identical t a)
-- | Get the 'Unlift' action for the current transformer layer.
--
-- Since 0.1.0
askUnlift :: forall t m. (MonadTransUnlift t, Monad m) => t m (Unlift t)
askUnlift = liftWith unlifter
where
unlifter :: (forall n b. Monad n => t n b -> n (StT t b)) -> m (Unlift t)
unlifter r = return $ Unlift (mkUnlift r)
-- | A simplified version of 'askUnlift' which addresses the common case where
-- polymorphism isn't necessary.
--
-- Since 0.1.0
askRun :: (MonadTransUnlift t, Monad (t m), Monad m) => t m (t m a -> m a)
askRun = liftM unlift askUnlift
{-# INLINE askRun #-}
-- | Similar to 'Unlift', but instead of moving one layer down the stack, moves
-- the action to the base monad.
--
-- Since 0.1.0
newtype UnliftBase b m = UnliftBase { unliftBase :: forall a. m a -> b a }
class (StM m a ~ a) => IdenticalBase m a
instance (StM m a ~ a) => IdenticalBase m a
-- | A monad transformer stack which can be unlifted, obeying the monad morphism laws.
--
-- Since 0.1.0
class (MonadBaseControl b m, Forall (IdenticalBase m)) => MonadBaseUnlift b m | m -> b
instance (MonadBaseControl b m, Forall (IdenticalBase m)) => MonadBaseUnlift b m
mkUnliftBase :: forall m a b. (Forall (IdenticalBase m), Monad b)
=> (forall c. m c -> b (StM m c)) -> m a -> b a
mkUnliftBase r act = r act \\ (inst :: Forall (IdenticalBase m) :- IdenticalBase m a)
-- | Get the 'UnliftBase' action for the current transformer stack.
--
-- Since 0.1.0
askUnliftBase :: forall b m. (MonadBaseUnlift b m) => m (UnliftBase b m)
askUnliftBase = liftBaseWith unlifter
where
unlifter :: (forall c. m c -> b (StM m c)) -> b (UnliftBase b m)
unlifter r = return $ UnliftBase (mkUnliftBase r)
-- | A simplified version of 'askUnliftBase' which addresses the common case
-- where polymorphism isn't necessary.
--
-- Since 0.1.0
askRunBase :: (MonadBaseUnlift b m)
=> m (m a -> b a)
askRunBase = liftM unliftBase askUnliftBase
{-# INLINE askRunBase #-}