diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -11,3 +11,13 @@
 ## 0.2.1.0 -- 2025-11-05
 
 * Exporting `lift`
+
+## 0.2.2.0 -- 2025-12-02
+
+* Adding `ResultT` synonym, `MonadExcept` class
+
+* Adding `ReaderT` and `StateT` helpers
+
+* Adding `withAsyncEffT'` helper, generalized certain type signatures
+
+* Adding Exception instances and `tryAndThrow` IO utilities
diff --git a/monad-effect.cabal b/monad-effect.cabal
--- a/monad-effect.cabal
+++ b/monad-effect.cabal
@@ -7,7 +7,7 @@
 -- PVP summary:     +-+------- breaking API changes
 --                  | | +----- non-breaking API additions
 --                  | | | +--- code changes with no API change
-version:            0.2.1.0
+version:            0.2.2.0
 
 -- A short (one-line) description of the package.
 synopsis:  A fast and lightweight effect system.
@@ -77,6 +77,7 @@
 
     -- Modules exported by the library.
     exposed-modules:  Control.Monad.Effect
+                    , Control.Monad.Class.Except
                     , Control.System
                     , Control.System.EventLoop
                     , Data.Result
diff --git a/src/Control/Monad/Class/Except.hs b/src/Control/Monad/Class/Except.hs
new file mode 100644
--- /dev/null
+++ b/src/Control/Monad/Class/Except.hs
@@ -0,0 +1,83 @@
+module Control.Monad.Class.Except where
+
+import Control.Exception as E
+import Control.Monad.Except
+import Data.Kind (Type)
+import Data.Proxy
+import Data.String (IsString)
+import Data.Text (Text, unpack, pack)
+import Data.Typeable (Typeable)
+import GHC.TypeLits
+
+-- | a newtype wrapper ErrorText that wraps a Text with a name (for example Symbol type)
+-- useful for creating ad-hoc error type
+--
+-- @
+-- ErrorText @_ @"FileNotFound" "information : file not found"
+-- @
+newtype ErrorText (s :: k) = ErrorText Text
+  deriving newtype (IsString)
+
+-- | Can be used to construct an ErrorText value, use type application to give the name
+--
+-- @
+-- errorText @"FileNotFound" "file not found"
+-- @
+errorText :: forall s. Text -> ErrorText s
+errorText = ErrorText
+{-# INLINE errorText #-}
+
+-- | a newtype wrapper ErrorValue that wraps a custom value type v with a name (for example Symbol type)
+-- useful for creating ad-hoc error type
+newtype ErrorValue (a :: k) (v :: Type) = ErrorValue v
+
+-- | Can be used to construct an ErrorValue value, use type application to give the name
+errorValue :: forall s v. v -> ErrorValue s v
+errorValue = ErrorValue
+{-# INLINE errorValue #-}
+
+-- | A wrapper dedicated for errors living in MonadThrow and MonadCatch
+newtype MonadThrowError = MonadThrowError SomeException
+  deriving Show
+
+instance KnownSymbol s => Show (ErrorText s) where
+  show (ErrorText t) = "ErrorText of type " ++ symbolVal (Proxy @s) ++ ": " ++ unpack t
+
+instance (KnownSymbol s, Show v) => Show (ErrorValue s v) where
+  show (ErrorValue v) = "ErrorValue of type " <> symbolVal (Proxy @s) <> ": " <> show v
+
+-- | @since 0.2.2.0
+instance KnownSymbol s                       => Exception (ErrorText s)
+
+-- | @since 0.2.2.0
+instance (KnownSymbol s, Typeable v, Show v) => Exception (ErrorValue s v)
+
+-- | Similar to MonadError, but with out the functional dependency so a monad can throw multiple exceptions.
+--
+-- @since 0.2.2.0
+class Monad m => MonadExcept e m where
+  throwExcept :: e -> m a
+
+-- | @since 0.2.2.0
+instance Exception e => MonadExcept e IO where
+  throwExcept = throwIO
+
+-- | @since 0.2.2.0
+instance MonadExcept e (Either e) where
+  throwExcept = Left
+
+-- | This instance allows throwing named textual errors in the Either monad.
+--
+-- @since 0.2.2.0
+instance KnownSymbol s => MonadExcept (ErrorText s) (Either (Text, Text)) where
+  throwExcept (ErrorText t) = Left (pack $ symbolVal (Proxy @s), t)
+
+-- | @since 0.2.2.0
+instance Monad m => MonadExcept e (ExceptT e m) where
+  throwExcept = throwError
+
+-- | This instance allows throwing named textual errors in the ExceptT monad transformer.
+--
+-- @since 0.2.2.0
+instance (Monad m, KnownSymbol s) => MonadExcept (ErrorText s) (ExceptT (Text, Text) m) where
+  throwExcept (ErrorText t) = throwError (pack $ symbolVal (Proxy @s), t)
diff --git a/src/Control/Monad/Effect.hs b/src/Control/Monad/Effect.hs
--- a/src/Control/Monad/Effect.hs
+++ b/src/Control/Monad/Effect.hs
@@ -1,11 +1,15 @@
 {-# LANGUAGE DerivingVia, AllowAmbiguousTypes, UndecidableInstances, LinearTypes, QuantifiedConstraints #-}
+{-# OPTIONS_GHC -Wno-unrecognised-pragmas #-}
+{-# HLINT ignore "Redundant lambda" #-}
 -- | Module: Control.Monad.Effect
 -- Description: The module you should import to use for effectful computation
 --
 -- This module provides the EffT monad transformer and various functions to work with it.
 module Control.Monad.Effect
-  ( -- * EffTectful computation
+  ( -- * Effectful computation
     EffT', Eff, Pure, EffT, EffL, PureL, EffLT
+  , IO', IO'L
+  , ResultT
   , ErrorText(..), errorText, ErrorValue(..), errorValue, MonadThrowError(..)
   , MonadFailError(..)
 
@@ -16,7 +20,8 @@
   , embedEffT, embedMods, embedError
 
   -- * Running EffT
-  , runEffT, runEffT_, runEffT0, runEffT01, runEffT00
+  , runEffT, runEffT_, runEffT0, runResultT
+  , runEffT01, runEffT00
   , runEffTNoError
   , runEffTOuter, runEffTOuter', runEffTOuter_
   , runEffTIn, runEffTIn', runEffTIn_
@@ -30,6 +35,8 @@
   -- * Catching exceptions from base
   , effTry, effTryIn, effTryWith, effTryInWith
   , effTryIO, effTryIOIn, effTryIOWith, effTryIOInWith
+  , effTryUncaught
+  , tryAndThrow, tryAndThrowWith, tryAndThrowText
 
   -- * Converting values to error
   , effEither, effEitherWith
@@ -42,7 +49,7 @@
   -- * Converting error to values
   , errorToEither, errorToEitherAll, eitherAllToEffect, errorInToEither
   , errorToMaybe, errorInToMaybe, errorToResult
-  
+
   -- * Transforming error
   , mapError
 
@@ -53,13 +60,15 @@
   , liftIOException, liftIOAt, liftIOSafeWith, liftIOText, liftIOPrepend
 
   -- * Bracket pattern
-  , maskEffT, generalBracketEffT, bracketEffT
+  , maskEffT, generalBracketEffT, bracketEffT, bracketOnErrorEffT
+  , generalBracketEffT', bracketEffT', bracketOnErrorEffT'
 
   -- * Looping
   , foreverEffT
 
   -- * Concurrency
-  , forkEffT, forkEffTFinally, forkEffTSafe, asyncEffT
+  , forkEffT, forkEffTFinally, forkEffTSafe
+  , asyncEffT, withAsyncEffT, withAsyncEffT'
   , restoreAsync, restoreAsync_
 
   -- * No Error
@@ -93,27 +102,28 @@
   ) where
 
 import Control.Concurrent
+import Control.Concurrent.STM
 import Control.Concurrent.Async
+import Control.Concurrent.Async.Internal (Async(..))
 import Control.Exception as E hiding (TypeError)
 import Control.Monad
 import Control.Monad.Base
 import Control.Monad.Catch as Catch
 import Control.Monad.IO.Class
 import Control.Monad.RS.Class
+import Control.Monad.Class.Except
 import Control.Monad.Trans
 import Control.Monad.Trans.Control
 import Data.Bifunctor
 import Data.Functor.Identity
 import Data.Kind
 import Data.Proxy
-import Data.String (IsString)
-import Data.Text (Text, unpack, pack)
-import Data.Type.Equality
+import Data.Text (Text, pack)
+import Data.Typeable
 import Data.TypeList
 import Data.TypeList.ConsFData.Pattern
 import Data.TypeList.FData
 import GHC.TypeError
-import GHC.TypeLits
 import GHC.Stack (HasCallStack)
 
 -- | EffTectful computation, using modules as units of effect
@@ -128,12 +138,19 @@
 type EffT  mods es  = EffT' FData mods es
 type Pure  mods es  = EffT' FData mods es Identity
 type In    mods es  = In'   FData mods es
+-- | Error list enhanced IO
+type IO'   es       = EffT' FData '[] es IO
+-- | A uniform replacement for ExceptT
+--
+-- @ since 0.2.2.0
+type ResultT es m = EffT' FData '[] es m
 
 -- | Short hand monads which uses FList instead of FData as the data structure
 type EffL  mods es = EffT' FList mods es IO
 type EffLT mods es = EffT' FList mods es
 type PureL mods es = EffT' FList mods es Identity
 type InL   mods es = In'   FList mods es
+type IO'L  es      = EffT' FList '[]  es IO
 
 -- | A constraint that checks the error list is empty in EffT
 type family MonadNoError m :: Constraint where
@@ -146,43 +163,6 @@
 checkNoError = id
 {-# INLINE checkNoError #-}
 
--- | a newtype wrapper ErrorText that wraps a Text with a name (for example Symbol type)
--- useful for creating ad-hoc error type
---
--- @
--- ErrorText @_ @"FileNotFound" "information : file not found"
--- @
-newtype ErrorText (s :: k) = ErrorText Text
-  deriving newtype (IsString)
-
--- | Can be used to construct an ErrorText value, use type application to give the name
---
--- @
--- errorText @"FileNotFound" "file not found"
--- @
-errorText :: forall s. Text -> ErrorText s
-errorText = ErrorText
-{-# INLINE errorText #-}
-
--- | a newtype wrapper ErrorValue that wraps a custom value type v with a name (for example Symbol type)
--- useful for creating ad-hoc error type
-newtype ErrorValue (a :: k) (v :: Type) = ErrorValue v
-
--- | Can be used to construct an ErrorValue value, use type application to give the name
-errorValue :: forall s v. v -> ErrorValue s v
-errorValue = ErrorValue
-{-# INLINE errorValue #-}
-
--- | A wrapper dedicated for errors living in MonadThrow and MonadCatch
-newtype MonadThrowError = MonadThrowError SomeException
-  deriving Show
-
-instance KnownSymbol s => Show (ErrorText s) where
-  show (ErrorText t) = "ErrorText of type " ++ symbolVal (Proxy @s) ++ ": " ++ unpack t
-
-instance (KnownSymbol s, Show v) => Show (ErrorValue s v) where
-  show (ErrorValue v) = "ErrorValue of type " <> symbolVal (Proxy @s) <> ": " <> show v
-
 instance Functor m => Functor (EffT' c mods es m) where
   fmap f (EffT' eff) = EffT' $ \rs ss -> first (fmap f) <$> eff rs ss
   {-# INLINE fmap #-}
@@ -283,6 +263,12 @@
   fail = effThrowIn . MonadFailError
   {-# INLINE fail #-}
 
+-- | Throw into the error list.
+--
+-- @since 0.2.2.0
+instance (Monad m, InList e es) => MonadExcept e (EffT' c mods es m) where
+  throwExcept = effThrowIn
+
 baseTransform :: ( forall a. m a -> n a ) -> EffT' c mods es m b -> EffT' c mods es n b
 baseTransform f = \(EffT' eff) -> EffT' $ \rs ss -> f (eff rs ss)
 {-# INLINE baseTransform #-}
@@ -308,8 +294,8 @@
   unEffT' (actionUsingUnmask $ \(EffT' eff) -> EffT' $ \rs' ss' -> unmask (eff rs' ss')) rs ss
 {-# INLINE maskEffT #-}
 
--- | The generalized bracket pattern for EffT
--- exceptions outside the error list are not caught.
+-- | The generalized bracket pattern for EffT.
+-- Exceptions outside the error list are NOT caught.
 -- To deal with them, make them into the error list first (like using effTryIOWith).
 generalBracketEffT
   :: MonadMask m
@@ -324,7 +310,28 @@
   release resource result
 {-# INLINABLE generalBracketEffT #-}
 
--- | A simpler version of `generalBracketEffT` where the release function does not depend on the result of the action and error types are the same.
+-- | The generalized bracket pattern for EffT.
+-- Exceptions outside the error list are also caught, you can rethrow them in the release function.
+--
+-- @since 0.2.2.0
+generalBracketEffT'
+  :: (MonadMask m, MonadCatch m, uncaught ~ ErrorValue "uncaught" SomeException)
+  => HasCallStack
+  => EffT' c mods es m a                        -- ^ acquire resource
+  -> (a -> Either uncaught (Result es' b) -> EffT' c mods es m o) -- ^ release resource, and return the result
+  -> (a -> EffT' c mods es' m b)                -- ^ action using the resource
+  -> EffT' c mods es m o
+generalBracketEffT' acquire release action = maskEffT $ \unMaskEffT -> do
+  resource <- acquire
+  result <- errorToEither $ effTryUncaught $ embedNoError $ unMaskEffT (errorToResult $ action resource)
+  release resource result
+{-# INLINABLE generalBracketEffT' #-}
+
+-- | A simpler version of `generalBracketEffT` where the release function does not depend on the result
+-- of the action and error types are the same.
+--
+-- The release function is run if the use action returns or fails with algebraic exceptions.
+-- Exceptions outside the error list are NOT caught.
 bracketEffT :: (MonadMask m, HasCallStack)
   => EffT' c mods es m a         -- ^ acquire resource
   -> (a -> EffT' c mods es m ()) -- ^ release resource only
@@ -338,9 +345,71 @@
   )
 {-# INLINABLE bracketEffT #-}
 
+-- | Like bracketEffT, but exceptions outside the error list are also caught and rethrown (SomeException),
+-- ensuring the release action is always run.
+--
+-- @since 0.2.2.0
+bracketEffT'
+  :: ( MonadMask m
+     , MonadCatch m
+     , HasCallStack
+     , MonadExcept SomeException m
+     )
+  => EffT' c mods es m a         -- ^ acquire resource
+  -> (a -> EffT' c mods es m ())  -- ^ release resource only
+  -> (a -> EffT' c mods es m b) -- ^ action using the resource
+  -> EffT' c mods es m b
+bracketEffT' acquire release = generalBracketEffT'
+  acquire
+  (\a result -> case result of
+      Right (RSuccess b) -> release a >> return b
+      Right (RFailure e) -> release a >> EffT' (\_ ss -> return (RFailure e, ss))
+      Left (ErrorValue uncaught) -> release a >> lift (throwExcept uncaught)
+  )
+{-# INLINABLE bracketEffT' #-}
+
+-- | Like bracketEffT, but the release function is only called when the inner computation fails with algebraic exception. If the use action normally returns (RSuccess), then the release action is not run.
+--
+-- @since 0.2.2.0
+bracketOnErrorEffT :: (MonadMask m, HasCallStack)
+  => EffT' c mods es m t
+  -> (t -> EffT' c mods es m a)
+  -> (t -> EffT' c mods es m o)
+  -> EffT' c mods es m o
+bracketOnErrorEffT acquire release = generalBracketEffT
+  acquire
+  (\a result -> case result of
+      RSuccess b -> return b
+      RFailure e -> release a >> EffT' (\_ ss -> return (RFailure e, ss))
+  )
+{-# INLINABLE bracketOnErrorEffT #-}
+
+-- | Like bracketOnErrorEffT, but exceptions outside the error list are also caught and rethrown (SomeException),
+-- ensuring the release action is always run.
+--
+-- @since 0.2.2.0
+bracketOnErrorEffT'
+  :: ( MonadMask m
+     , MonadCatch m
+     , HasCallStack
+     , MonadExcept SomeException m
+     )
+  => EffT' c mods es m t
+  -> (t -> EffT' c mods es m a)
+  -> (t -> EffT' c mods es m o)
+  -> EffT' c mods es m o
+bracketOnErrorEffT' acquire release = generalBracketEffT'
+  acquire
+  (\a result -> case result of
+      Right (RSuccess b) -> return b
+      Right (RFailure e) -> release a >> EffT' (\_ ss -> return (RFailure e, ss))
+      Left (ErrorValue uncaught) -> release a >> lift (throwExcept uncaught)
+  )
+{-# INLINABLE bracketOnErrorEffT' #-}
+
 -- | The states on the separate thread will diverge, and will be discarded.
 -- when exception occurs, the thread quits
-forkEffT :: forall c mods es m. (MonadIO m, MonadBaseControl IO m) => EffT' c mods es m () -> EffT' c mods NoError m ThreadId
+forkEffT :: forall c mods es m noError ignored. (MonadBaseControl IO m) => EffT' c mods es m ignored -> EffT' c mods noError m ThreadId
 forkEffT eff = EffT' $ \rs ss -> do
   -- run the EffT' computation in a separate thread
   forkedEff <- liftBaseWith $ \runInBase -> forkIO (void $ runInBase $ unEffT' eff rs ss)
@@ -359,7 +428,7 @@
   => EffT' c mods es m a
   -> ((Result (AddIfNotElem SomeAsyncException es) a, SystemState c mods) -> EffT' c mods NoError m ())
   -> EffT' c mods noError m ThreadId
-forkEffTFinally eff finalizer = embedError $ do
+forkEffTFinally eff finalizer = do
   rs <- query
   ss <- get
   maskEffT $ \unmask -> forkEffT $ do
@@ -371,16 +440,85 @@
 forkEffTSafe :: forall c mods m. (MonadIO m, MonadBaseControl IO m) => EffT' c mods NoError m () -> EffT' c mods NoError m ThreadId
 forkEffTSafe = forkEffT
 {-# INLINE forkEffTSafe #-}
+{-# DEPRECATED forkEffTSafe "The name of this funciton is confusing, will be remove in the future." #-}
 
 -- | The states on the separate thread will diverge, and will be returned as an Async type.
 asyncEffT
-  :: forall c mods es m a. (MonadBaseControl IO m)
-  => EffT' c mods es m a -> EffT' c mods NoError m (Async (StM m (Result es a, SystemState c mods)))
+  :: forall c mods es m a result.
+      ( MonadBaseControl IO m
+      , result ~ StM m (Result es a, SystemState c mods)
+      )
+  => EffT' c mods es m a -> EffT' c mods NoError m (Async result)
 asyncEffT eff = EffT' $ \rs ss -> do
   asyncEff <- liftBaseWith $ \runInBase -> async (runInBase $ unEffT' eff rs ss)
   return (RSuccess asyncEff, ss)
 {-# INLINE asyncEffT #-}
 
+-- | Generalized version of withAsync, spawn asynchronous action in separate thread.
+--
+-- * When the use handle (second argument) encounters algebraic exception / returns normally
+--
+-- * Or when the async action (first argument) ends in any possible way, (algebraic / SomeException / returns)
+--
+-- the async thread will be killed with uninterruptibleCancel.
+--
+-- * try @SomeException is used on the async action,
+-- to be compatible with the classic Async type definition.
+--
+-- @since 0.2.2.0
+withAsyncEffT
+  :: forall c mods es es' m a b eff eff' result
+  . ( MonadBaseControl IO m
+    , MonadMask m
+    , eff  ~ EffT' c mods es  m
+    , eff' ~ EffT' c mods es' m
+    , result ~ StM m (Result es' a, SystemState c mods)
+    )
+  => eff' a -> (Async result -> eff b) -> eff b
+withAsyncEffT = \action use -> do
+  tmvar <- liftBase newEmptyTMVarIO
+  maskEffT $ \unmaskEffT -> do
+    tid <- embedNoError $ declareNoError $ liftBaseWith $ \runInBase ->
+      forkIO $ E.try @SomeException (runInBase $ unmaskEffT action)
+        >>= liftBase . atomically . writeTMVar tmvar
+    let asyncHandle = Async tid (readTMVar tmvar)
+    r <- use asyncHandle `effCatchAll` \e -> do
+      liftBase $ uninterruptibleCancel asyncHandle
+      effThrowEList e
+    liftBase $ uninterruptibleCancel asyncHandle
+    return r
+{-# INLINABLE withAsyncEffT #-}
+
+-- | Similar to withAsyncEffT, but also catches (and rethrows) uncaught exceptions
+-- in the second argument.
+--
+-- @since 0.2.2.0
+withAsyncEffT'
+  :: forall c mods es es' m a b eff eff' result
+  . ( MonadBaseControl IO m
+    , MonadExcept SomeException m
+    , MonadMask m
+    , eff  ~ EffT' c mods es  m
+    , eff' ~ EffT' c mods es' m
+    , result ~ StM m (Result es' a, SystemState c mods)
+    )
+  => eff' a -> (Async result -> eff b) -> eff b
+withAsyncEffT' = \action use -> do
+  tmvar <- liftBase newEmptyTMVarIO
+  maskEffT $ \unmaskEffT -> do
+    tid <- embedNoError $ declareNoError $ liftBaseWith $ \runInBase ->
+      forkIO $ E.try @SomeException (runInBase $ unmaskEffT action)
+        >>= liftBase . atomically . writeTMVar tmvar
+    let asyncHandle = Async tid (readTMVar tmvar)
+    eR <- errorToEither (effTryUncaught (use asyncHandle)) `effCatchAll` \e -> do
+      liftBase $ uninterruptibleCancel asyncHandle
+      effThrowEList e
+    liftBase $ uninterruptibleCancel asyncHandle
+    case eR of
+      Right a             -> return a
+      Left (ErrorValue e) -> lift $ throwExcept e
+{-# INLINABLE withAsyncEffT' #-}
+
 -- | Restores the EffT' computation from an Async value created by asyncEffT.
 -- State will be replaced by the state inside the Async when it finishes.
 restoreAsync ::
@@ -468,6 +606,12 @@
 runEffT0 = fmap fst . runEffT fNil fNil
 {-# INLINE runEffT0 #-}
 
+-- | Synonym for runEffT0 for ResultT
+--
+-- @since 0.2.2.0
+runResultT :: Monad m => ResultT es m a -> m (Result es a)
+runResultT = runEffT0
+
 -- | runs the EffT' with no modules and a single possible error type, return as classic Either type
 runEffT01 :: (Monad m, ConsFNil c) => EffT' c '[] '[e] m a -> m (Either e a)
 runEffT01 = fmap (first fromElistSingleton . resultToEither) . runEffT0
@@ -725,6 +869,34 @@
     Right (eResult, stateMods) -> return (eResult, stateMods)
 {-# INLINE effTryIOInWith #-}
 
+-- | Can be useful for catching all exceptions in the base monad (those that are unhandled by your algebraic exception list).
+-- For example to be used at the outmost layer of the app, or inside bracket patterns.
+effTryUncaught :: MonadCatch m => EffT' c mods es m a -> EffT' c mods (ErrorValue "uncaught" SomeException : es) m a
+effTryUncaught = effTryWith @SomeException (errorValue @"uncaught")
+
+-------------------------------------- try (IO) and throw using MonadExcept ---------------------------------
+-- | Alternative way to liftIO and try, to catch specific exception type and utilize the MonadExcept instance
+--
+-- @since 0.2.2.0
+tryAndThrowWith :: forall e e' m a. (MonadIO m, E.Exception e, MonadExcept e' m) => (e -> e') -> IO a -> m a
+tryAndThrowWith using = either (throwExcept . using) return <=< liftIO . E.try @e
+
+-- | Similar to tryAndThrowWith, uses id
+--
+-- @since 0.2.2.0
+tryAndThrow :: forall e m a. (MonadIO m, E.Exception e, MonadExcept e m) => IO a -> m a
+tryAndThrow = tryAndThrowWith @e id
+
+-- | Directly show the exception and throw it as ErrorText. Use two type applications to specify the error types.
+--
+-- @
+-- tryAndThrowText @IOException @"FileNotFound" $ readFile' "file.txt"
+-- @
+--
+-- @since 0.2.2.0
+tryAndThrowText :: forall e symb m a. (MonadIO m, E.Exception e, MonadExcept (ErrorText symb) m) => IO a -> m a
+tryAndThrowText = tryAndThrowWith @e (errorText @symb . pack . show)
+
 -- | Transform the first error in the error list
 mapError :: Monad m => (e1 -> e2) -> EffT' c mods (e1 : es) m a -> EffT' c mods (e2 : es) m a
 mapError f eff = EffT' $ \rs ss -> do
@@ -841,7 +1013,7 @@
 
 -- | Catch all errors in the error list, and handle it with a handler function. You can pattern match on `EList es` to handle the errors.
 -- Removes all errors from the error list.
-effCatchAll :: Monad m => EffT' c mods es m a -> (EList es -> EffT' c mods NoError m a) -> EffT' c mods NoError m a
+effCatchAll :: Monad m => EffT' c mods es m a -> (EList es -> EffT' c mods noError m a) -> EffT' c mods noError m a
 effCatchAll eff h = EffT' $ \rs ss -> do
   (er, stateMods) <- unEffT' eff rs ss
   case er of
@@ -866,6 +1038,7 @@
 effThrowEListIn :: forall es es' c mods m a. (Monad m, NonEmptySubList es es') => EList es -> EffT' c mods es' m a
 effThrowEListIn es = EffT' $ \_ s -> pure (RFailure $ subListEListEmbed es, s)
 {-# INLINE effThrowEListIn #-}
+
 
 -- | Turn an Either return type into the error list with a function, adding the error type if it is not already in the error list.
 -- The inner monad type needs to be precise due to the way type inference works.
diff --git a/src/Module/RS.hs b/src/Module/RS.hs
--- a/src/Module/RS.hs
+++ b/src/Module/RS.hs
@@ -14,7 +14,8 @@
 import Data.TypeList
 import Data.Bifunctor (second)
 import GHC.TypeLits
-import qualified Control.Monad.State as S
+import qualified Control.Monad.State  as S
+import qualified Control.Monad.Reader as R
 
 import Control.System
 
@@ -70,6 +71,50 @@
   withModule (SInitData s) = runEffTOuter_ SRead (SState s)
   {-# INLINE withModule #-}
 instance EventLoop c (SModule s) mods es
+
+liftReaderT :: forall r mods errs m c a. (Monad m, In' c (RModule r) mods) => R.ReaderT r m a -> EffT' c mods errs m a
+liftReaderT rAction = do
+  RRead r <- askModule @(RModule r)
+  lift $ R.runReaderT rAction r
+{-# INLINE liftReaderT #-}
+
+embedReaderT :: forall r mods errs m c a. (Monad m, In' c (RModule r) mods) => R.ReaderT r (EffT' c mods errs m) a -> EffT' c mods errs m a
+embedReaderT action = do
+  RRead r <- askModule @(RModule r)
+  embedEffT $ R.runReaderT action r
+{-# INLINE embedReaderT #-}
+
+addReaderT :: forall r mods errs m c a.
+  ( SubList c mods (RModule r : mods)
+  , RModule r `NotIn` mods
+  , In' c (RModule r) (RModule r : mods)
+  , Monad m
+  )
+  => R.ReaderT r (EffT' c mods errs m) a -> EffT' c (RModule r : mods) errs m a
+addReaderT action = do
+  RRead r <- askModule @(RModule r)
+  embedEffT $ R.runReaderT action r
+{-# INLINE addReaderT #-}
+
+asReaderT :: forall r mods errs m c a.
+  ( In' c (RModule r) mods
+  , RModule r `UniqueIn` mods
+  , SubList c (Remove (FirstIndex (RModule r) mods) mods) mods
+  , Monad m
+  )
+  => R.ReaderT r (EffT' c (Remove (FirstIndex (RModule r) mods) mods) errs m) a -> EffT' c mods errs m a
+asReaderT action = do
+  RRead r <- askModule
+  embedEffT $ R.runReaderT action r
+{-# INLINE asReaderT #-}
+
+liftStateT :: forall s mods errs m c a. (Monad m, In' c (SModule s) mods) => S.StateT s m a -> EffT' c mods errs m a
+liftStateT sAction = do
+  SState s <- getModule @(SModule s)
+  (a, s') <- lift $ S.runStateT sAction s
+  putModule @(SModule s) (SState s')
+  return a
+{-# INLINE liftStateT #-}
 
 embedStateT :: forall s mods errs m c a. (Monad m, In' c (SModule s) mods) => S.StateT s (EffT' c mods errs m) a -> EffT' c mods errs m a
 embedStateT action = do
