packages feed

monadology-0.2: src/Control/Monad/Ology/General/Trans/Unlift.hs

module Control.Monad.Ology.General.Trans.Unlift where

import Control.Monad.Ology.General.Extract
import Control.Monad.Ology.General.Function
import Control.Monad.Ology.General.IO
import Control.Monad.Ology.General.Outer
import Control.Monad.Ology.General.Trans.Constraint
import Control.Monad.Ology.General.Trans.Hoist
import Control.Monad.Ology.General.Trans.Tunnel
import Control.Monad.Ology.Specific.ComposeOuter
import Import

class ( MonadTransTunnel t
      , TransConstraint MonadFail t
      , TransConstraint MonadIO t
      , TransConstraint MonadFix t
      , TransConstraint Monad t
      , MonadExtract (Tunnel t)
      ) => MonadTransUnlift t where
    -- | Lift with an unlifting function that accounts for the transformer's effects (using MVars where necessary).
    liftWithUnlift ::
           forall m r. MonadIO m
        => (Unlift MonadTunnelIO t -> m r)
        -> t m r
    -- | Return an unlifting function that discards the transformer's effects (such as state change or output).
    getDiscardingUnlift ::
           forall m. Monad m
        => t m (WUnlift MonadTunnelIO t)
    getDiscardingUnlift = tunnel $ \unlift -> pure $ pure $ MkWUnlift $ \tma -> fmap mToValue $ unlift tma

toDiscardingUnlift ::
       forall t. MonadTransUnlift t
    => Unlift MonadUnliftIO t
    -> Unlift MonadUnliftIO t
toDiscardingUnlift run tmr = do
    MkWUnlift du <- run getDiscardingUnlift
    du tmr

wLiftWithUnlift ::
       forall t m. (MonadTransUnlift t, MonadTunnelIO m)
    => WBackraised m (t m)
wLiftWithUnlift = MkWBackraised $ \call -> liftWithUnlift $ \unlift -> call unlift

composeUnliftRaised :: (MonadTransUnlift t, MonadUnliftIO m) => Unlift Functor t -> (m --> n) -> (t m --> n)
composeUnliftRaised rt rm tma = rm $ rt tma

composeUnliftRaisedCommute ::
       (MonadTransUnlift t, MonadUnliftIO m, MonadUnliftIO n) => Unlift Functor t -> (m --> n) -> (t m --> n)
composeUnliftRaisedCommute rt rm tma = rt $ hoist rm tma

class (MonadFail m, MonadIO m, MonadFix m, MonadTunnelIO m, MonadExtract (TunnelIO m)) => MonadUnliftIO m where
    -- | Lift with an unlifting function that accounts for the effects over 'IO'.
    liftIOWithUnlift :: IO -/-> m
    -- | Return an unlifting function that discards the effects over 'IO'.
    getDiscardingIOUnlift :: m (WRaised m IO)
    getDiscardingIOUnlift = tunnelIO $ \unlift -> pure $ pure $ MkWRaised $ \mr -> fmap mToValue $ unlift mr

wLiftIOWithUnlift :: MonadUnliftIO m => WBackraised IO m
wLiftIOWithUnlift = MkWBackraised liftIOWithUnlift

instance MonadUnliftIO IO where
    liftIOWithUnlift call = call id

instance (MonadTransUnlift t, MonadUnliftIO m, MonadFail (t m), MonadIO (t m), MonadFix (t m)) => MonadUnliftIO (t m) where
    liftIOWithUnlift call = liftWithUnlift $ \tmama -> liftIOWithUnlift $ \maioa -> call $ maioa . tmama

instance MonadTransUnlift t => TransConstraint MonadUnliftIO t where
    hasTransConstraint =
        withTransConstraintDict @MonadFail $ withTransConstraintDict @MonadIO $ withTransConstraintDict @MonadFix $ Dict

instance MonadOuter outer => MonadTransUnlift (ComposeOuter outer) where
    liftWithUnlift call =
        MkComposeOuter $ do
            MkWExtract extract <- getExtract
            return $ call $ extract . unComposeOuter

monoHoist ::
       forall (t :: TransKind) ma mb a b. (MonadTransUnlift t, MonadTunnelIO ma, MonadIO mb)
    => (ma a -> mb b)
    -> (t ma a -> t mb b)
monoHoist f tma = liftWithUnlift $ \unlift -> f $ unlift tma