diff --git a/Example/DatabaseProvider/Main.hs b/Example/DatabaseProvider/Main.hs
--- a/Example/DatabaseProvider/Main.hs
+++ b/Example/DatabaseProvider/Main.hs
@@ -10,17 +10,20 @@
     Effect,
     Emb,
     Freer,
+    RemoveExps,
+    UnliftIO,
     interprets,
     liftIO,
     makeEffectF,
     makeEffectH,
     nil,
-    runEff,
     (!:),
     type (:>),
     type (~>),
  )
-import Control.Monad.Hefty.Provider (Provider, provide_, runProvider_)
+import Control.Monad.Hefty.Provider (Provider, provide_, runRegionProvider_)
+import Control.Monad.Hefty.Unlift (runUnliftIO)
+import Data.Effect.OpenUnion (WeakenExps)
 import Data.Functor.Identity (Identity)
 
 data DatabaseF :: Effect where
@@ -34,9 +37,11 @@
 
 type DBProvider es = Provider Freer Identity FilePath '[DatabaseH, DatabaseF] es
 
-runDummyDBProvider :: (Emb IO :> es) => Eff (DBProvider es ': es) ~> Eff es
+runDummyDBProvider
+    :: (UnliftIO :> es, Emb IO :> es, Emb IO :> RemoveExps es, WeakenExps es)
+    => Eff (DBProvider (RemoveExps es) ': es) ~> Eff es
 runDummyDBProvider =
-    runProvider_ \workDir ->
+    runRegionProvider_ @IO \workDir ->
         interprets $
             ( \(TransactDB m) -> do
                 liftIO $ putStrLn $ "[DUMMY DB " <> workDir <> "] START TRANSACTION"
@@ -55,7 +60,7 @@
 
 main :: IO ()
 main =
-    runEff . runDummyDBProvider $
+    runUnliftIO . runDummyDBProvider $
         provide_ "/db1" \_ -> do
             provide_ "/db2" \detach -> do
                 detach do
diff --git a/README.md b/README.md
--- a/README.md
+++ b/README.md
@@ -1,25 +1,29 @@
-# Heftia: higher-order algebraic effects done right
+# Heftia: A theory‑backed, ultra type‑safe algebraic effects
 
 [![Hackage](https://img.shields.io/hackage/v/heftia.svg?logo=haskell&label=heftia)](https://hackage.haskell.org/package/heftia)
 [![Hackage](https://img.shields.io/hackage/v/heftia-effects.svg?logo=haskell&label=heftia-effects)](https://hackage.haskell.org/package/heftia-effects)
 [![Stackage LTS](https://www.stackage.org/package/heftia-effects/badge/lts)](https://www.stackage.org/lts/package/heftia-effects)
 [![Stackage Nightly](https://www.stackage.org/package/heftia-effects/badge/nightly)](https://www.stackage.org/nightly/package/heftia-effects)
-[![Build status](https://img.shields.io/github/actions/workflow/status/sayo-hs/heftia/haskell.yml?branch=develop)](https://github.com/sayo-hs/heftia/actions)
+[![Build status](https://img.shields.io/github/actions/workflow/status/sayo-hs/heftia/haskell.yml?branch=master)](https://github.com/sayo-hs/heftia/actions)
 
-Heftia is an extensible effects library for Haskell that generalizes "Algebraic Effects and Handlers" to higher-order effects, providing users with maximum flexibility and delivering standard and reasonable speed.
-In its generalization, the focus is on ensuring predictable results based on simple, consistent semantics, while preserving soundness.
+Heftia is a Haskell library for algebraic effects grounded in solid theoretical foundations.
 
-Please refer to the [Haddock documentation](https://hackage.haskell.org/package/heftia-0.6.0.0/docs/Control-Monad-Hefty.html) for usage and semantics.
-For information on performance, please refer to [performance.md](https://github.com/sayo-hs/heftia/blob/v0.6.0/benchmark/performance.md).
+It is the only library that fully supports higher-order algebraic effects with complete type safety.
 
+Say goodbye to runtime errors and unsound semantics.
+
+This library provides a simple interface, predictable behavior, and maximum flexibility while delivering standard, practical performance.
+
+Please refer to the [Haddock documentation](https://hackage.haskell.org/package/heftia-0.7.0.0/docs/Control-Monad-Hefty.html) for usage and semantics.
+For information on performance, please refer to [performance.md](https://github.com/sayo-hs/heftia/blob/v0.7.0.0/benchmark/performance.md).
+
 This library is inspired by the paper:
-* Casper Bach Poulsen and Cas van der Rest. 2023. Hefty Algebras: Modular
-    Elaboration of Higher-Order Algebraic Effects. Proc. ACM Program. Lang. 7,
-    POPL, Article 62 (January 2023), 31 pages. <https://doi.org/10.1145/3571255>
+* [Hefty Algebras: Modular Elaboration of Higher-Order Algebraic Effects. Casper Bach Poulsen & Cas van der Rest, POPL 2023.](https://doi.org/10.1145/3571255)
 
-The *elaboration* approach proposed in the above paper allows for a straightforward treatment of higher-order effects.
+The elaboration approach proposed in that paper allows for a straightforward treatment of higher-order effects.
 
-Heftia's data structure is an extension of the Freer monad, designed to be theoretically straightforward by eliminating ad-hoc elements.
+Heftia is also grounded in the following theory:
+* [A Framework for Higher-Order Effects & Handlers. Birthe van den Berg & Tom Schrijvers, Sci. Comput. Program. 2024.](https://doi.org/10.1016/j.scico.2024.103086)
 
 ## Why choose this library over others?
 This library is based on algebraic effects. Currently, **none of the practical effect libraries other than this one are "algebraic."** So, why is being *algebraic* important?
@@ -44,7 +48,7 @@
 If performance is particularly important, [`effectful`](https://github.com/haskell-effectful/effectful) would be the best alternative to this library.
 
 [^8]: MonadUnliftIO instance allows escape https://github.com/tomjaguarpaw/bluefin/issues/29
-[^9]: [heftia-effects/test/Test/UnliftIO.hs](https://github.com/sayo-hs/heftia/blob/v0.6.0/heftia-effects/test/Test/UnliftIO.hs)
+[^9]: [heftia-effects/test/Test/UnliftIO.hs](https://github.com/sayo-hs/heftia/blob/v0.7.0.0/heftia-effects/test/Test/UnliftIO.hs)
 
 ## Key Features
 
@@ -60,34 +64,34 @@
     * Higher-order effects
         * [`MonadUnliftIO`](https://hackage.haskell.org/package/unliftio)
             * to prevent resource leaks due to runtime exceptions
-            * [heftia-effects/Example/UnliftIO/Main.hs](https://github.com/sayo-hs/heftia/blob/v0.6.0/heftia-effects/Example/UnliftIO/Main.hs)
-            * [heftia-effects/Example/Stream/Main.hs](https://github.com/sayo-hs/heftia/blob/v0.6.0/heftia-effects/Example/Stream/Main.hs)
+            * [heftia-effects/Example/UnliftIO/Main.hs](https://github.com/sayo-hs/heftia/blob/v0.7.0.0/heftia-effects/Example/UnliftIO/Main.hs)
+            * [heftia-effects/Example/Stream/Main.hs](https://github.com/sayo-hs/heftia/blob/v0.7.0.0/heftia-effects/Example/Stream/Main.hs)
         * [`Provider`](https://hackage.haskell.org/package/effectful-core-2.5.0.0/docs/Effectful-Provider.html) a.k.a. [`Scoped`](https://hackage.haskell.org/package/polysemy-1.9.2.0/docs/Polysemy-Scoped.html)
             * to prevent [resource handles from leaking out of scopes](https://h2.jaguarpaw.co.uk/posts/bluefin-prevents-handles-leaking/)
-            * [Control.Monad.Hefty.Concurrent.Subprocess](https://hackage.haskell.org/package/heftia-effects-0.6.0.0/docs/Control-Monad-Hefty-Concurrent-Subprocess.html)
-            * [heftia-effects/Example/Subprocess/Main.hs](https://github.com/sayo-hs/heftia/blob/v0.6.0/heftia-effects/Example/Subprocess/Main.hs)
-            * [heftia-effects/Example/FileSystemProvider/Main.hs](https://github.com/sayo-hs/heftia/blob/v0.6.0/heftia-effects/Example/FileSystemProvider/Main.hs)
+            * [Control.Monad.Hefty.Concurrent.Subprocess](https://hackage.haskell.org/package/heftia-effects-0.7.0.0/docs/Control-Monad-Hefty-Concurrent-Subprocess.html)
+            * [heftia-effects/Example/Subprocess/Main.hs](https://github.com/sayo-hs/heftia/blob/v0.7.0.0/heftia-effects/Example/Subprocess/Main.hs)
+            * [heftia-effects/Example/DatabaseProvider/Main.hs](https://github.com/sayo-hs/heftia/blob/v0.7.0.0/heftia-effects/Example/DatabaseProvider/Main.hs)
         * [Applicative-style Parallelism](https://medium.com/@PerrottaFrancisco/learning-cats-effects-parallel-execution-f617f883e390)
             * like `cats-effect` in Scala
-            * [Data.Effect.Concurrent.Parallel](https://hackage.haskell.org/package/data-effects-0.3.0.1/docs/Data-Effect-Concurrent-Parallel.html)
-            * [Control.Monad.Hefty.Concurrent.Parallel](https://hackage.haskell.org/package/heftia-effects-0.6.0.0/docs/Control-Monad-Hefty-Concurrent-Parallel.html)
-            * [heftia-effects/test/Test/Concurrent.hs](https://github.com/sayo-hs/heftia/blob/v0.6.0/heftia-effects/test/Test/Concurrent.hs)
+            * [Data.Effect.Concurrent.Parallel](https://hackage.haskell.org/package/data-effects-0.4.2.0/docs/Data-Effect-Concurrent-Parallel.html)
+            * [Control.Monad.Hefty.Concurrent.Parallel](https://hackage.haskell.org/package/heftia-effects-0.7.0.0/docs/Control-Monad-Hefty-Concurrent-Parallel.html)
+            * [heftia-effects/test/Test/Concurrent.hs](https://github.com/sayo-hs/heftia/blob/v0.7.0.0/heftia-effects/test/Test/Concurrent.hs)
 
     All of these interact through a simple, consistent, and predictable semantics based on algebraic effects.
 
 * **Easy and Concise Implementation for Custom Effect Interpreters**
 
-    As you can see from the implementations of basic effect interpreters such as [State](https://hackage.haskell.org/package/heftia-effects-0.6.0.0/docs/src/Control.Monad.Hefty.State.html#runState), [Throw/Catch](https://hackage.haskell.org/package/heftia-effects-0.6.0.0/docs/src/Control.Monad.Hefty.Except.html#runThrow), [Writer](https://hackage.haskell.org/package/heftia-effects-0.6.0.0/docs/src/Control.Monad.Hefty.Writer.html#runTell), [NonDet](https://hackage.haskell.org/package/heftia-effects-0.6.0.0/docs/src/Control.Monad.Hefty.NonDet.html#runNonDet), and [Coroutine](https://hackage.haskell.org/package/heftia-effects-0.6.0.0/docs/src/Control.Monad.Hefty.Coroutine.html#runCoroutine), they can be implemented in just a few lines, or even a single line. Even for effects like NonDet and Coroutine, which involve continuations and might seem difficult to implement at first glance, this is exactly how simple it can be. This is the power of algebraic effects. Users can quickly define experimental and innovative custom effects using continuations.
+    As you can see from the implementations of basic effect interpreters such as [State](https://hackage.haskell.org/package/heftia-effects-0.7.0.0/docs/src/Control.Monad.Hefty.State.html#runState), [Throw/Catch](https://hackage.haskell.org/package/heftia-effects-0.7.0.0/docs/src/Control.Monad.Hefty.Except.html#runThrow), [Writer](https://hackage.haskell.org/package/heftia-effects-0.7.0.0/docs/src/Control.Monad.Hefty.Writer.html#runTell), [NonDet](https://hackage.haskell.org/package/heftia-effects-0.7.0.0/docs/src/Control.Monad.Hefty.NonDet.html#runNonDet), and [Coroutine](https://hackage.haskell.org/package/heftia-effects-0.7.0.0/docs/src/Control.Monad.Hefty.Coroutine.html#runCoroutine), they can be implemented in just a few lines, or even a single line. Even for effects like NonDet and Coroutine, which involve continuations and might seem difficult to implement at first glance, this is exactly how simple it can be. This is the power of algebraic effects. Users can quickly define experimental and innovative custom effects using continuations.
 
 * **Standard and Reasonable Performance**
 
-    It operates at a speed positioned roughly in the middle between faster libraries (like `effectful` or `eveff`) and relatively slower ones (like `polysemy` or `fused-effects`): [performance.md](https://github.com/sayo-hs/heftia/blob/v0.6.0/benchmark/performance.md).
+    It operates at a speed roughly on par with `effectful` and significantly faster than `mtl` and `polysemy`: [performance.md](https://github.com/sayo-hs/heftia/blob/v0.7.0.0/benchmark/performance.md).
 
 * **Type Safety and Purity**
 
     * Does not depend on the IO monad and can use any monad as the base monad.
     * Semantics are isolated from the IO monad, meaning that aspects like asynchronous exceptions and threads do not affect the behavior of effects.
-    * The constructors of the `Eff` monad are [exposed](https://hackage.haskell.org/package/heftia-0.6.0.0/docs/Control-Monad-Hefty.html#t:Eff), and users can manipulate them directly without any safety concerns. Still, the semantics remain intact.
+    * The constructors of the `Eff` monad are [exposed](https://hackage.haskell.org/package/heftia-0.7.0.0/docs/Control-Monad-Hefty.html#t:Eff), and users can manipulate them directly without any safety concerns. Still, the semantics remain intact.
     * These are in contrast to libraries like `effectful` and `eff`, making this library more **Haskell-ish and purely functional**.
     * **This design effectively prevents obscure behaviors and potential runtime errors.**
 
@@ -124,7 +128,7 @@
     ```console
     $ cabal update
     ```
-2. Add `heftia-effects ^>= 0.6` to the build dependencies. Enable the `GHC2021` and the following language extensions as needed:
+2. Add `heftia-effects ^>= 0.7` to the build dependencies. Enable the `GHC2021` and the following language extensions as needed:
 
     * `LambdaCase`
     * `DerivingStrategies`
@@ -142,7 +146,7 @@
 ...
     build-depends:
         ...
-        heftia-effects ^>= 0.6,
+        heftia-effects ^>= 0.7,
 
     default-language: GHC2021
 
@@ -265,11 +269,11 @@
 
 * `End` is displayed just after the first sequence ends and before the second sequence starts. This demonstrates that the `bracket_` function based on `MonadUnliftIO` for safe resource release works in such a way that resources are released immediately at the correct timing—even if the stream is still in progress—rather than waiting until the entire stream (including the second sequence) has completed. Existing stream libraries like [`pipes`](https://hackage.haskell.org/package/pipes) and [`conduit`](https://hackage.haskell.org/package/conduit) have the issue that immediate resource release like this is not possible. This problem was first addressed by the effect system library [`bluefin`](https://github.com/tomjaguarpaw/bluefin). For more details, please refer to [Bluefin streams finalize promptly](https://h2.jaguarpaw.co.uk/posts/bluefin-streams-finalize-promptly/).
 
-The complete code example can be found at [heftia-effects/Example/Stream/Main.hs](https://github.com/sayo-hs/heftia/blob/v0.6.0/heftia-effects/Example/Stream/Main.hs).
+The complete code example can be found at [heftia-effects/Example/Stream/Main.hs](https://github.com/sayo-hs/heftia/blob/v0.7.0.0/heftia-effects/Example/Stream/Main.hs).
 
 ### Aggregating File Sizes Using Non-Deterministic Computation
 
-The following is an extract of the main parts from an example of non-deterministic computation. For the full code, please refer to [heftia-effects/Example/NonDet/Main.hs](https://github.com/sayo-hs/heftia/blob/v0.6.0/heftia-effects/Example/NonDet/Main.hs).
+The following is an extract of the main parts from an example of non-deterministic computation. For the full code, please refer to [heftia-effects/Example/NonDet/Main.hs](https://github.com/sayo-hs/heftia/blob/v0.7.0.0/heftia-effects/Example/NonDet/Main.hs).
 
 ```haskell
 -- | Aggregate the sizes of all files under the given path
@@ -340,8 +344,8 @@
 ```
 
 ## Documentation
-A detailed explanation of usage and semantics is available in [Haddock](https://hackage.haskell.org/package/heftia-0.6.0.0/docs/Control-Monad-Hefty.html).
-The example codes are located in the [heftia-effects/Example/](https://github.com/sayo-hs/heftia/tree/v0.6.0/heftia-effects/Example) directory.
+A detailed explanation of usage and semantics is available in [Haddock](https://hackage.haskell.org/package/heftia-0.7.0.0/docs/Control-Monad-Hefty.html).
+The example codes are located in the [heftia-effects/Example/](https://github.com/sayo-hs/heftia/tree/v0.7.0.0/heftia-effects/Example) directory.
 Also, the following *HeftWorld* example (outdated): https://github.com/sayo-hs/HeftWorld
 
 About the internal *elaboration* mechanism: https://sayo-hs.github.io/jekyll/update/2024/09/04/how-the-heftia-extensible-effects-library-works.html
@@ -368,7 +372,7 @@
 | `freer-simple`      | ❌                   | Multi-shot             | ✅            | ✅                                | ✅                       | Algebraic Effects                |
 | `polysemy`          | ✅                   | ❌                     | ✅            | ✅                                | ✅                       | Weaving-based (functorial state) |
 | `effectful`         | ✅                   | ❌                     | ✅            | ❌ (based on the `IO` monad)      | ✅                       | IO-fused                         |
-| `bluefin`           | ❌[^7]               | ❌                     | ✅            | ❌ (based on the `IO` monad)      | [^5]                     | IO-fused                         |
+| `bluefin`           | ✅[^7][^10]          | ❌                     | ✅            | ❌ (based on the `IO` monad)      | ✅[^5]                   | IO-fused                         |
 | `eff`               | ✅                   | Multi-shot             | ✅            | ❌ (based on the `IO` monad)      | ✅                       | Algebraic Effects & IO-fused [^6]|
 | `speff`             | ✅                   | Multi-shot (restriction: [^4]) | ✅    | ❌ (based on the `IO` monad)      | ✅                       | Algebraic Effects & IO-fused     |
 | `mtl`               | ✅                   | Multi-shot (`ContT`)   | ✅            | ✅                                | ❌                       | Carrier dependent                |
@@ -383,6 +387,7 @@
 [^5]: https://discourse.haskell.org/t/bluefin-compared-to-effectful-video/10723/27?u=ymdfield
 [^6]: https://github.com/hasura/eff/issues/12
 [^7]: https://discourse.haskell.org/t/what-is-a-higher-order-effect/10744
+[^10]: https://github.com/tomjaguarpaw/bluefin/pull/27
 
 Heftia can simply be described as a higher-order version of `freer-simple`.
 This is indeed true in terms of its internal mechanisms as well.
@@ -399,10 +404,10 @@
 
 ### Performance
 
-Overall, the performance of this library is positioned roughly in the middle between the fast (`effectful`, `eveff`, etc.) and slow (`polysemy`, `fused-effects`, etc.) libraries, and can be considered average.
-In all benchmarks, the speed is nearly equivalent to `freer-simple`, only slightly slower.
+Overall, the performance of this library is roughly on par with `effectful`, or only slightly slower.
+`heftia` runs significantly faster compared to existing effect systems such as `mtl` and `polysemy`.
 
-For more details, please refer to [performance.md](https://github.com/sayo-hs/heftia/blob/v0.6.0/benchmark/performance.md).
+For more details, please refer to [performance.md](https://github.com/sayo-hs/heftia/blob/v0.7.0.0/benchmark/performance.md).
 
 ### Interoperability with other libraries
 
@@ -435,13 +440,13 @@
 * (Support for [Linear](https://hackage.haskell.org/package/linear-base) effects?)
 
 ## License
-The license is MPL 2.0. Please refer to the [NOTICE](https://github.com/sayo-hs/heftia/blob/v0.6.0/NOTICE).
+The license is MPL 2.0. Please refer to the [NOTICE](https://github.com/sayo-hs/heftia/blob/v0.7.0.0/NOTICE).
 Additionally, the code from `freer-simple` has been modified and used internally within this library.
 Therefore, some modules are licensed under both `MPL-2.0 AND BSD-3-Clause`.
 For details on licenses and copyrights, please refer to the module's Haddock documentation.
 
 ## Your contributions are welcome!
-Please see [CONTRIBUTING.md](https://github.com/sayo-hs/heftia/blob/v0.6.0/CONTRIBUTING.md).
+Please see [CONTRIBUTING.md](https://github.com/sayo-hs/heftia/blob/v0.7.0.0/CONTRIBUTING.md).
 
 ## Acknowledgements, citations, and related work
 The following is a non-exhaustive list of people and works that have had a significant impact, directly or indirectly, on Heftia’s design and implementation:
diff --git a/bench/BenchCatch.hs b/bench/BenchCatch.hs
--- a/bench/BenchCatch.hs
+++ b/bench/BenchCatch.hs
@@ -1,3 +1,5 @@
+{-# LANGUAGE CPP #-}
+
 -- SPDX-License-Identifier: BSD-3-Clause
 -- (c) 2022 Xy Ren; 2024 Sayo contributors
 
@@ -19,7 +21,9 @@
 import Polysemy qualified as P
 import Polysemy.Error qualified as P
 import Polysemy.Reader qualified as P
+#ifdef VERSION_eff
 import "eff" Control.Effect qualified as E
+#endif
 
 programHeftia :: (H.Throw () H.:> es, H.Catch () H.:> es) => Int -> H.Eff es a
 programHeftia = \case
@@ -84,6 +88,7 @@
   where
     run = EL.runReader ()
 
+#ifdef VERSION_eff
 programEff :: (E.Error () E.:< es) => Int -> E.Eff es a
 programEff = \case
     0 -> E.throw ()
@@ -97,6 +102,7 @@
 catchEffDeep n = E.run $ run $ run $ run $ run $ run $ E.runError $ run $ run $ run $ run $ run $ programEff n
   where
     run = E.runReader ()
+#endif
 
 programMtl :: (M.MonadError () m) => Int -> m a
 programMtl = \case
diff --git a/bench/BenchCoroutine.hs b/bench/BenchCoroutine.hs
--- a/bench/BenchCoroutine.hs
+++ b/bench/BenchCoroutine.hs
@@ -1,19 +1,24 @@
+{-# LANGUAGE CPP #-}
+
 -- SPDX-License-Identifier: BSD-3-Clause
 -- (c) 2022 Xy Ren; 2024 Sayo contributors
 
 module BenchCoroutine where
 
 import Control.Monad (forM)
+#ifdef VERSION_freer_simple
 import Control.Monad.Freer qualified as FS
 import Control.Monad.Freer.Coroutine qualified as FS
 import Control.Monad.Freer.Reader qualified as FS
+#endif
 import Control.Monad.Hefty qualified as H
 import Control.Monad.Hefty.Coroutine qualified as H
 import Control.Monad.Hefty.Reader qualified as H
-import Control.Mp.Eff qualified as Mp
-import Control.Mp.Util qualified as Mp
+#ifdef VERSION_eff
 import "eff" Control.Effect qualified as E
+#endif
 
+#ifdef VERSION_freer_simple
 programFreer :: (FS.Member (FS.Yield Int Int) es) => Int -> FS.Eff es [Int]
 programFreer upbound =
     forM [1 .. upbound] (`FS.yield` id)
@@ -32,6 +37,7 @@
 coroutineFreerDeep n = FS.run $ run $ run $ run $ run $ run $ loopStatusFreer =<< FS.runC (run $ run $ run $ run $ run $ programFreer n)
   where
     run = FS.runReader ()
+#endif
 
 programHeftia :: (H.Yield Int Int H.:> es) => Int -> H.Eff es [Int]
 programHeftia upbound =
@@ -53,6 +59,7 @@
     run :: H.Eff (H.Ask () ': es) a -> H.Eff es a
     run = H.runAsk ()
 
+#ifdef VERSION_eff
 programEff :: (E.Coroutine Int Int E.:< es) => Int -> E.Eff es [Int]
 programEff upbound =
     forM [1 .. upbound] $ E.yield @Int @Int
@@ -71,26 +78,4 @@
 coroutineEffDeep n = E.run $ run $ run $ run $ run $ run $ loopStatusEff =<< E.runCoroutine (run $ run $ run $ run $ run $ programEff n)
   where
     run = E.runReader ()
-
-programMp :: (MpYield Int Int Mp.:? e) => Int -> Mp.Eff e [Int]
-programMp n = forM [0 .. n] $ \i -> Mp.perform mpYield i
-{-# NOINLINE programMp #-}
-
-loopStatusMp :: H.Status (Mp.Eff e) Int Int r -> Mp.Eff e r
-loopStatusMp = \case
-    H.Done r -> pure r
-    H.Continue a k -> loopStatusMp =<< k (a + 100)
-{-# NOINLINE loopStatusMp #-}
-
-coroutineMp :: Int -> [Int]
-coroutineMp n = Mp.runEff $ loopStatusMp =<< mpCoroutine @Int @Int (programMp n)
-
-coroutineMpDeep :: Int -> [Int]
-coroutineMpDeep n = Mp.runEff $ run $ run $ run $ run $ run $ loopStatusMp =<< mpCoroutine @Int @Int (run $ run $ run $ run $ run $ programMp n)
-  where
-    run = Mp.reader ()
-
-newtype MpYield a b e ans = MpYield {mpYield :: Mp.Op a b e ans}
-
-mpCoroutine :: Mp.Eff (MpYield a b Mp.:* e) r -> Mp.Eff e (H.Status (Mp.Eff e) a b r)
-mpCoroutine = Mp.handler MpYield {mpYield = Mp.operation $ \a k -> pure $ H.Continue a k} . fmap H.Done
+#endif
diff --git a/bench/BenchCountdown.hs b/bench/BenchCountdown.hs
--- a/bench/BenchCountdown.hs
+++ b/bench/BenchCountdown.hs
@@ -1,3 +1,5 @@
+{-# LANGUAGE CPP #-}
+
 -- SPDX-License-Identifier: BSD-3-Clause
 -- (c) 2022 Xy Ren; 2024 Sayo contributors
 
@@ -6,11 +8,11 @@
 
 import Control.Carrier.Reader qualified as F
 import Control.Carrier.State.Strict qualified as F
-import Control.Ev.Eff qualified as E
-import Control.Ev.Util qualified as E
+#ifdef VERSION_freer_simple
 import Control.Monad.Freer qualified as FS
 import Control.Monad.Freer.Reader qualified as FS
 import Control.Monad.Freer.State qualified as FS
+#endif
 import Control.Monad.Hefty qualified as H
 import Control.Monad.Hefty.Reader qualified as H
 import Control.Monad.Hefty.State qualified as H
@@ -23,7 +25,9 @@
 import Polysemy qualified as P
 import Polysemy.Reader qualified as P
 import Polysemy.State qualified as P
+#ifdef VERSION_eff
 import "eff" Control.Effect qualified as EF
+#endif
 
 programHeftia :: (H.State Int H.:> es) => H.Eff es Int
 programHeftia = do
@@ -50,6 +54,7 @@
 hrunR :: H.Eff (H.Ask () ': es) a -> H.Eff es a
 hrunR = H.runAsk ()
 
+#ifdef VERSION_freer_simple
 programFreer :: (FS.Member (FS.State Int) es) => FS.Eff es Int
 programFreer = do
     x <- FS.get @Int
@@ -67,6 +72,7 @@
 countdownFreerDeep n = FS.run $ runR $ runR $ runR $ runR $ runR $ FS.runState n $ runR $ runR $ runR $ runR $ runR $ programFreer
   where
     runR = FS.runReader ()
+#endif
 
 programSem :: (P.Member (P.State Int) es) => P.Sem es Int
 programSem = do
@@ -123,6 +129,7 @@
   where
     runR = EL.runReader ()
 
+#ifdef VERSION_eff
 programEff :: (EF.State Int EF.:< es) => EF.Eff es Int
 programEff = do
     x <- EF.get @Int
@@ -140,30 +147,7 @@
 countdownEffDeep n = EF.run $ runR $ runR $ runR $ runR $ runR $ EF.runState n $ runR $ runR $ runR $ runR $ runR $ programEff
   where
     runR = EF.runReader ()
-
-programEv :: (E.State Int E.:? es) => E.Eff es Int
-programEv = do
-    x <- E.perform (E.get @Int) ()
-    if x == 0
-        then pure x
-        else do
-            E.perform E.put (x - 1)
-            programEv
-{-# NOINLINE programEv #-}
-
-countdownEv :: Int -> (Int, Int)
-countdownEv n = E.runEff $ runStateEv n programEv
-
-countdownEvDeep :: Int -> (Int, Int)
-countdownEvDeep n = E.runEff $ runR $ runR $ runR $ runR $ runR $ runStateEv n $ runR $ runR $ runR $ runR $ runR $ programEv
-  where
-    runR = E.reader ()
-
-runStateEv :: s -> E.Eff (E.State s E.:* es) a -> E.Eff es (s, a)
-runStateEv s0 m = E.state s0 do
-    r <- m
-    s <- E.perform E.get ()
-    pure (s, r)
+#endif
 
 programMtl :: (M.MonadState Int m) => m Int
 programMtl = do
diff --git a/bench/BenchFileSizes.hs b/bench/BenchFileSizes.hs
new file mode 100644
--- /dev/null
+++ b/bench/BenchFileSizes.hs
@@ -0,0 +1,651 @@
+{-# LANGUAGE AllowAmbiguousTypes #-}
+{-# LANGUAGE BlockArguments #-}
+{-# LANGUAGE CPP #-}
+{-# LANGUAGE TemplateHaskell #-}
+{-# LANGUAGE UndecidableInstances #-}
+{-# HLINT ignore "Use camelCase" #-}
+{-# OPTIONS_GHC -Wno-unrecognised-pragmas #-}
+
+-- SPDX-License-Identifier: BSD-3-Clause
+-- (c) 2021-2022, Andrzej Rybczak; 2024 Sayo contributors
+
+module BenchFileSizes where
+
+import Control.Exception (IOException, try)
+import Control.Monad.IO.Class (MonadIO (..))
+import Data.IORef (IORef, modifyIORef', newIORef, readIORef)
+import Data.Text (Text)
+import Data.Text qualified as T
+import System.Posix (fileSize, getFileStatus)
+
+-- effectful
+import Effectful qualified as E
+import Effectful.Dispatch.Dynamic qualified as E
+import Effectful.Reader.Static qualified as E
+import Effectful.State.Static.Local qualified as E
+
+-- eff
+#ifdef VERSION_eff
+import "eff" Control.Effect qualified as L
+#endif
+
+-- cleff
+#ifdef VERSION_cleff
+import Cleff qualified as C
+import Cleff.Reader qualified as C
+import Cleff.State qualified as C
+#endif
+
+-- freer-simple
+#ifdef VERSION_freer_simple
+import Control.Monad.Freer qualified as FS
+import Control.Monad.Freer.Reader qualified as FS
+import Control.Monad.Freer.State qualified as FS
+#endif
+
+-- fused-effects
+#ifdef VERSION_fused_effects
+import Control.Algebra qualified as FE
+import Control.Effect.Sum qualified as FE
+import Control.Carrier.Reader qualified as FE
+import Control.Carrier.State.Strict qualified as FE
+#endif
+
+-- mtl
+#ifdef VERSION_mtl
+import Control.Monad.State qualified as M
+import Control.Monad.Reader qualified as M
+#endif
+
+-- polysemy
+#ifdef VERSION_polysemy
+import Polysemy qualified as P
+import Polysemy.Reader qualified as P
+import Polysemy.State qualified as P
+#endif
+
+-- heftia
+import Control.Monad.Hefty qualified as H
+import Control.Monad.Hefty.Reader qualified as H
+import Control.Monad.Hefty.State qualified as H
+
+tryGetFileSize :: FilePath -> IO (Maybe Int)
+tryGetFileSize path =
+    try @IOException (getFileStatus path) >>= \case
+        Left _ -> pure Nothing
+        Right stat -> pure . Just . fromIntegral $ fileSize stat
+
+----------------------------------------
+-- reference
+
+ref_calculateFileSize :: IORef [Text] -> FilePath -> IO Int
+ref_calculateFileSize logs path = do
+    logToIORef logs $ "Calculating the size of " ++ path
+    tryGetFileSize path >>= \case
+        Nothing -> 0 <$ logToIORef logs ("Could not calculate the size of " ++ path)
+        Just size -> size <$ logToIORef logs (path ++ " is " ++ show size ++ " bytes")
+  where
+    logToIORef :: IORef [Text] -> String -> IO ()
+    logToIORef r msgS = do
+        let msg = T.pack msgS
+        msg `seq` modifyIORef' r (msg :)
+{-# NOINLINE ref_calculateFileSize #-}
+
+ref_program :: IORef [Text] -> [FilePath] -> IO Int
+ref_program logs files = do
+    sizes <- traverse (ref_calculateFileSize logs) files
+    pure $ sum sizes
+{-# NOINLINE ref_program #-}
+
+ref_calculateFileSizes :: [FilePath] -> IO (Int, [Text])
+ref_calculateFileSizes files = do
+    logs <- newIORef []
+    size <- ref_program logs files
+    finalLogs <- readIORef logs
+    pure (size, finalLogs)
+
+----------------------------------------
+-- heftia
+
+data Heftia_File :: H.Effect where
+    Heftia_tryFileSize :: FilePath -> Heftia_File f (Maybe Int)
+H.makeEffectF ''Heftia_File
+
+heftia_runFile :: (H.Emb IO H.:> es) => H.Eff (Heftia_File : es) a -> H.Eff es a
+heftia_runFile = H.interpret \case
+    Heftia_tryFileSize path -> liftIO $ tryGetFileSize path
+
+data Heftia_Logging :: H.Effect where
+    Heftia_logMsg :: !Text -> Heftia_Logging f ()
+H.makeEffectF ''Heftia_Logging
+
+heftia_runLogging :: (H.FOEs es) => H.Eff (Heftia_Logging : es) a -> H.Eff es ([Text], a)
+heftia_runLogging =
+    H.runState [] . H.reinterpret \case
+        Heftia_logMsg msg -> H.modify (msg :)
+
+----------
+
+heftia_calculateFileSize
+    :: (Heftia_File H.:> es, Heftia_Logging H.:> es)
+    => FilePath
+    -> H.Eff es Int
+heftia_calculateFileSize path = do
+    heftia_logMsg $ T.pack $ "Calculating the size of " ++ path
+    heftia_tryFileSize path >>= \case
+        Nothing -> 0 <$ heftia_logMsg (T.pack $ "Could not calculate the size of " ++ path)
+        Just size -> size <$ heftia_logMsg (T.pack $ path ++ " is " ++ show size ++ " bytes")
+{-# NOINLINE heftia_calculateFileSize #-}
+
+heftia_program
+    :: (Heftia_File H.:> es, Heftia_Logging H.:> es)
+    => [FilePath]
+    -> H.Eff es Int
+heftia_program files = do
+    sizes <- traverse heftia_calculateFileSize files
+    pure $ sum sizes
+{-# NOINLINE heftia_program #-}
+
+heftia_calculateFileSizes :: [FilePath] -> IO ([Text], Int)
+heftia_calculateFileSizes =
+    H.runEff . heftia_runFile . heftia_runLogging . heftia_program
+
+heftia_calculateFileSizesDeep :: [FilePath] -> IO ([Text], Int)
+heftia_calculateFileSizesDeep =
+    H.runEff
+        . runR
+        . runR
+        . runR
+        . runR
+        . runR
+        . heftia_runFile
+        . heftia_runLogging
+        . runR
+        . runR
+        . runR
+        . runR
+        . runR
+        . heftia_program
+  where
+    runR = H.runAsk ()
+
+----------------------------------------
+-- effectful
+
+data Effectful_File :: E.Effect where
+    Effectful_tryFileSize :: FilePath -> Effectful_File m (Maybe Int)
+
+type instance E.DispatchOf Effectful_File = 'E.Dynamic
+
+effectful_tryFileSize :: (Effectful_File E.:> es) => FilePath -> E.Eff es (Maybe Int)
+effectful_tryFileSize = E.send . Effectful_tryFileSize
+
+effectful_runFile :: (E.IOE E.:> es) => E.Eff (Effectful_File : es) a -> E.Eff es a
+effectful_runFile = E.interpret_ \case
+    Effectful_tryFileSize path -> liftIO $ tryGetFileSize path
+
+data Effectful_Logging :: E.Effect where
+    Effectful_logMsg :: !Text -> Effectful_Logging m ()
+
+type instance E.DispatchOf Effectful_Logging = 'E.Dynamic
+
+effectful_logMsg :: (Effectful_Logging E.:> es) => String -> E.Eff es ()
+effectful_logMsg = E.send . Effectful_logMsg . T.pack
+
+effectful_runLogging
+    :: E.Eff (Effectful_Logging : es) a
+    -> E.Eff es (a, [Text])
+effectful_runLogging = E.reinterpret_ (E.runState []) \case
+    Effectful_logMsg msg -> E.modify (msg :)
+
+----------
+
+effectful_calculateFileSize
+    :: (Effectful_File E.:> es, Effectful_Logging E.:> es)
+    => FilePath
+    -> E.Eff es Int
+effectful_calculateFileSize path = do
+    effectful_logMsg $ "Calculating the size of " ++ path
+    effectful_tryFileSize path >>= \case
+        Nothing -> 0 <$ effectful_logMsg ("Could not calculate the size of " ++ path)
+        Just size -> size <$ effectful_logMsg (path ++ " is " ++ show size ++ " bytes")
+{-# NOINLINE effectful_calculateFileSize #-}
+
+effectful_program
+    :: (Effectful_File E.:> es, Effectful_Logging E.:> es)
+    => [FilePath]
+    -> E.Eff es Int
+effectful_program files = do
+    sizes <- traverse effectful_calculateFileSize files
+    pure $ sum sizes
+{-# NOINLINE effectful_program #-}
+
+effectful_calculateFileSizes :: [FilePath] -> IO (Int, [Text])
+effectful_calculateFileSizes =
+    E.runEff . effectful_runFile . effectful_runLogging . effectful_program
+
+effectful_calculateFileSizesDeep :: [FilePath] -> IO (Int, [Text])
+effectful_calculateFileSizesDeep =
+    E.runEff
+        . runR
+        . runR
+        . runR
+        . runR
+        . runR
+        . effectful_runFile
+        . effectful_runLogging
+        . runR
+        . runR
+        . runR
+        . runR
+        . runR
+        . effectful_program
+  where
+    runR = E.runReader ()
+
+----------------------------------------
+-- eff
+
+#ifdef VERSION_eff
+
+data Eff_File :: L.Effect where
+  Eff_tryFileSize :: FilePath -> Eff_File m (Maybe Int)
+
+eff_tryFileSize :: Eff_File L.:< es => FilePath -> L.Eff es (Maybe Int)
+eff_tryFileSize = L.send . Eff_tryFileSize
+
+eff_runFile :: L.IOE L.:< es => L.Eff (Eff_File : es) a -> L.Eff es a
+eff_runFile = L.interpret \case
+  Eff_tryFileSize path -> liftIO $ tryGetFileSize path
+
+data Eff_Logging :: L.Effect where
+  Eff_logMsg :: !Text -> Eff_Logging m ()
+
+eff_logMsg :: Eff_Logging L.:< es => String -> L.Eff es ()
+eff_logMsg = L.send . Eff_logMsg . T.pack
+
+eff_runLogging
+  :: L.Eff (Eff_Logging : es) a
+  -> L.Eff es ([Text], a)
+eff_runLogging
+  = L.runState [] . L.interpret \case
+      Eff_logMsg msg -> L.modify (msg :)
+  . L.lift
+
+----------
+
+eff_calculateFileSize
+  :: (Eff_File L.:< es, Eff_Logging L.:< es)
+  => FilePath
+  -> L.Eff es Int
+eff_calculateFileSize path = do
+  eff_logMsg $ "Calculating the size of " ++ path
+  eff_tryFileSize path >>= \case
+    Nothing   -> 0    <$ eff_logMsg ("Could not calculate the size of " ++ path)
+    Just size -> size <$ eff_logMsg (path ++ " is " ++ show size ++ " bytes")
+{-# NOINLINE eff_calculateFileSize #-}
+
+eff_program
+  :: (Eff_File L.:< es, Eff_Logging L.:< es)
+  => [FilePath]
+  -> L.Eff es Int
+eff_program files = do
+  sizes <- traverse eff_calculateFileSize files
+  pure $ sum sizes
+{-# NOINLINE eff_program #-}
+
+eff_calculateFileSizes :: [FilePath] -> IO ([Text], Int)
+eff_calculateFileSizes =
+  L.runIO . eff_runFile . eff_runLogging . eff_program
+
+eff_calculateFileSizesDeep :: [FilePath] -> IO ([Text], Int)
+eff_calculateFileSizesDeep = L.runIO
+  . runR . runR . runR . runR . runR
+  . eff_runFile . eff_runLogging
+  . runR . runR . runR . runR . runR
+  . eff_program
+  where
+    runR = L.runReader ()
+
+#endif
+
+----------------------------------------
+-- cleff
+
+#ifdef VERSION_cleff
+
+data Cleff_File :: C.Effect where
+  Cleff_tryFileSize :: FilePath -> Cleff_File m (Maybe Int)
+
+cleff_tryFileSize :: Cleff_File C.:> es => FilePath -> C.Eff es (Maybe Int)
+cleff_tryFileSize = C.send . Cleff_tryFileSize
+
+cleff_runFile :: C.IOE C.:> es => C.Eff (Cleff_File : es) a -> C.Eff es a
+cleff_runFile = C.interpret \case
+  Cleff_tryFileSize path -> liftIO $ tryGetFileSize path
+
+data Cleff_Logging :: C.Effect where
+  Cleff_logMsg :: !Text -> Cleff_Logging m ()
+
+cleff_logMsg :: Cleff_Logging C.:> es => String -> C.Eff es ()
+cleff_logMsg = C.send . Cleff_logMsg . T.pack
+
+cleff_runLogging
+  :: C.Eff (Cleff_Logging : es) a
+  -> C.Eff es (a, [Text])
+cleff_runLogging = C.runState [] . C.reinterpret \case
+  Cleff_logMsg msg -> C.modify (msg :)
+
+----------
+
+cleff_calculateFileSize
+  :: (Cleff_File C.:> es, Cleff_Logging C.:> es)
+  => FilePath
+  -> C.Eff es Int
+cleff_calculateFileSize path = do
+  cleff_logMsg $ "Calculating the size of " ++ path
+  cleff_tryFileSize path >>= \case
+    Nothing   -> 0    <$ cleff_logMsg ("Could not calculate the size of " ++ path)
+    Just size -> size <$ cleff_logMsg (path ++ " is " ++ show size ++ " bytes")
+{-# NOINLINE cleff_calculateFileSize #-}
+
+cleff_program
+  :: (Cleff_File C.:> es, Cleff_Logging C.:> es)
+  => [FilePath]
+  -> C.Eff es Int
+cleff_program files = do
+  sizes <- traverse cleff_calculateFileSize files
+  pure $ sum sizes
+{-# NOINLINE cleff_program #-}
+
+cleff_calculateFileSizes :: [FilePath] -> IO (Int, [Text])
+cleff_calculateFileSizes =
+  C.runIOE . cleff_runFile . cleff_runLogging . cleff_program
+
+cleff_calculateFileSizesDeep :: [FilePath] -> IO (Int, [Text])
+cleff_calculateFileSizesDeep = C.runIOE
+  . runR . runR . runR . runR . runR
+  . cleff_runFile . cleff_runLogging
+  . runR . runR . runR . runR . runR
+  . cleff_program
+  where
+    runR = C.runReader ()
+
+#endif
+
+----------------------------------------
+-- freer-simple
+
+#ifdef VERSION_freer_simple
+
+data FS_File r where
+  FS_tryFileSize :: FilePath -> FS_File (Maybe Int)
+
+fs_tryFileSize :: FS.Member FS_File es => FilePath -> FS.Eff es (Maybe Int)
+fs_tryFileSize = FS.send . FS_tryFileSize
+
+fs_runFile :: FS.LastMember IO es => FS.Eff (FS_File : es) a -> FS.Eff es a
+fs_runFile = FS.interpret \case
+  FS_tryFileSize path -> liftIO $ tryGetFileSize path
+
+data FS_Logging r where
+  FS_logMsg :: !Text -> FS_Logging ()
+
+fs_logMsg :: FS.Member FS_Logging es => String -> FS.Eff es ()
+fs_logMsg = FS.send . FS_logMsg . T.pack
+
+fs_runLogging
+  :: FS.Eff (FS_Logging : es) a
+  -> FS.Eff es (a, [Text])
+fs_runLogging = FS.runState [] . FS.reinterpret \case
+  FS_logMsg msg -> FS.modify (msg :)
+
+----------
+
+fs_calculateFileSize
+  :: (FS.Member FS_File es, FS.Member FS_Logging es)
+  => FilePath
+  -> FS.Eff es Int
+fs_calculateFileSize path = do
+  fs_logMsg $ "Calculating the size of " ++ path
+  fs_tryFileSize path >>= \case
+    Nothing   -> 0    <$ fs_logMsg ("Could not calculate the size of " ++ path)
+    Just size -> size <$ fs_logMsg (path ++ " is " ++ show size ++ " bytes")
+{-# NOINLINE fs_calculateFileSize #-}
+
+fs_program
+  :: (FS.Member FS_File es, FS.Member FS_Logging es)
+  => [FilePath]
+  -> FS.Eff es Int
+fs_program files = do
+  sizes <- traverse fs_calculateFileSize files
+  pure $ sum sizes
+{-# NOINLINE fs_program #-}
+
+fs_calculateFileSizes :: [FilePath] -> IO (Int, [Text])
+fs_calculateFileSizes =
+  FS.runM . fs_runFile . fs_runLogging . fs_program
+
+fs_calculateFileSizesDeep :: [FilePath] -> IO (Int, [Text])
+fs_calculateFileSizesDeep = FS.runM
+  . runR . runR . runR . runR . runR
+  . fs_runFile . fs_runLogging
+  . runR . runR . runR . runR . runR
+  . fs_program
+  where
+    runR = FS.runReader ()
+
+#endif
+
+----------------------------------------
+-- fused-effects
+
+#ifdef VERSION_fused_effects
+
+data FE_File :: E.Effect where
+  FE_tryFileSize :: FilePath -> FE_File m (Maybe Int)
+
+fe_tryFileSize :: FE.Has FE_File sig m => FilePath -> m (Maybe Int)
+fe_tryFileSize = FE.send . FE_tryFileSize
+
+newtype FE_FileC m a = FE_FileC { fe_runFileC :: m a }
+  deriving newtype (Applicative, Functor, Monad, MonadIO)
+
+instance
+  ( MonadIO m
+  , FE.Algebra sig m
+  ) => FE.Algebra (FE_File FE.:+: sig) (FE_FileC m) where
+  alg hdl sig ctx = case sig of
+    FE.L (FE_tryFileSize path) -> (<$ ctx) <$> liftIO (tryGetFileSize path)
+    FE.R other                 -> FE_FileC $ FE.alg (fe_runFileC . hdl) other ctx
+
+data FE_Logging :: E.Effect where
+  FE_logMsg :: !Text -> FE_Logging m ()
+
+fe_logMsg :: FE.Has FE_Logging sig m => String -> m ()
+fe_logMsg = FE.send . FE_logMsg . T.pack
+
+newtype FE_LoggingC m a = FE_LoggingC { fe_runLoggingC :: FE.StateC [Text] m a }
+  deriving newtype (Applicative, Functor, Monad)
+
+instance
+  ( FE.Algebra sig m
+  ) => FE.Algebra (FE_Logging FE.:+: sig) (FE_LoggingC m) where
+  alg hdl sig ctx = case sig of
+    FE.L (FE_logMsg msg) -> FE_LoggingC $ ctx <$ FE.modify (msg :)
+    FE.R other           -> FE_LoggingC $ FE.alg (fe_runLoggingC . hdl) (FE.R other) ctx
+
+fe_runLogging :: FE_LoggingC m a -> m ([Text], a)
+fe_runLogging = FE.runState [] . fe_runLoggingC
+
+----------
+
+fe_calculateFileSize
+  :: (FE.Member FE_File sig, FE.Member FE_Logging sig, FE.Algebra sig m)
+  => FilePath
+  -> m Int
+fe_calculateFileSize path = do
+  fe_logMsg $ "Calculating the size of " ++ path
+  fe_tryFileSize path >>= \case
+    Nothing   -> 0    <$ fe_logMsg ("Could not calculate the size of " ++ path)
+    Just size -> size <$ fe_logMsg (path ++ " is " ++ show size ++ " bytes")
+{-# NOINLINE fe_calculateFileSize #-}
+
+fe_program
+  :: (FE.Member FE_File sig, FE.Member FE_Logging sig, FE.Algebra sig m)
+  => [FilePath]
+  -> m Int
+fe_program files = do
+  sizes <- traverse fe_calculateFileSize files
+  pure $ sum sizes
+{-# NOINLINE fe_program #-}
+
+fe_calculateFileSizes :: [FilePath] -> IO ([Text], Int)
+fe_calculateFileSizes = fe_runFileC . fe_runLogging . fe_program
+
+fe_calculateFileSizesDeep :: [FilePath] -> IO ([Text], Int)
+fe_calculateFileSizesDeep
+  = runR . runR . runR . runR . runR
+  . fe_runFileC . fe_runLogging
+  . runR . runR . runR . runR . runR
+  . fe_program
+  where
+    runR = FE.runReader ()
+
+#endif
+
+----------------------------------------
+-- mtl
+
+#ifdef VERSION_mtl
+
+class Monad m => MonadFile m where
+  mtl_tryFileSize :: FilePath -> m (Maybe Int)
+
+newtype FileT m a = FileT { runFileT :: m a }
+  deriving newtype (Functor, Applicative, Monad, MonadIO)
+
+instance M.MonadTrans FileT where
+  lift = FileT
+
+instance {-# OVERLAPPABLE #-}
+  ( MonadFile m
+  , Monad (t m)
+  , M.MonadTrans t
+  ) => MonadFile (t m) where
+  mtl_tryFileSize = M.lift . mtl_tryFileSize
+
+instance MonadIO m => MonadFile (FileT m) where
+  mtl_tryFileSize path = liftIO $ tryGetFileSize path
+
+class Monad m => MonadLog m where
+  mtl_logMsg :: String -> m ()
+
+newtype LoggingT m a = LoggingT (M.StateT [Text] m a)
+  deriving newtype (Functor, Applicative, Monad, MonadIO, M.MonadTrans)
+
+instance {-# OVERLAPPABLE #-}
+  ( MonadLog m
+  , Monad (t m)
+  , M.MonadTrans t
+  ) => MonadLog (t m) where
+  mtl_logMsg = M.lift . mtl_logMsg
+
+instance MonadIO m => MonadLog (LoggingT m) where
+  mtl_logMsg msgS = do
+    let msg = T.pack msgS
+    msg `seq` LoggingT (M.modify (msg :))
+
+runLoggingT :: LoggingT m a -> m (a, [Text])
+runLoggingT (LoggingT m) = M.runStateT m []
+
+----------
+
+mtl_calculateFileSize :: (MonadLog m, MonadFile m) => FilePath -> m Int
+mtl_calculateFileSize path = do
+  mtl_logMsg $ "Calculating the size of " ++ path
+  mtl_tryFileSize path >>= \case
+    Nothing   -> 0    <$ mtl_logMsg ("Could not calculate the size of " ++ path)
+    Just size -> size <$ mtl_logMsg (path ++ " is " ++ show size ++ " bytes")
+{-# NOINLINE mtl_calculateFileSize #-}
+
+mtl_program :: (MonadLog m, MonadFile m) => [FilePath] -> m Int
+mtl_program files = do
+  sizes <- traverse mtl_calculateFileSize files
+  pure $ sum sizes
+{-# NOINLINE mtl_program #-}
+
+mtl_calculateFileSizes :: [FilePath] -> IO (Int, [Text])
+mtl_calculateFileSizes = runFileT . runLoggingT . mtl_program
+
+mtl_calculateFileSizesDeep :: [FilePath] -> IO (Int, [Text])
+mtl_calculateFileSizesDeep
+  = runR . runR . runR . runR . runR
+  . runFileT . runLoggingT
+  . runR . runR . runR . runR . runR
+  . mtl_program
+  where
+    runR = flip M.runReaderT ()
+
+#endif
+
+----------------------------------------
+-- polysemy
+
+#ifdef VERSION_polysemy
+
+data Poly_File :: E.Effect where
+  Poly_tryFileSize :: FilePath -> Poly_File m (Maybe Int)
+
+poly_tryFileSize :: P.Member Poly_File es => FilePath -> P.Sem es (Maybe Int)
+poly_tryFileSize = P.send . Poly_tryFileSize
+
+poly_runFile :: P.Member (P.Embed IO) es => P.Sem (Poly_File : es) a -> P.Sem es a
+poly_runFile = P.interpret \case
+  Poly_tryFileSize path -> P.embed $ tryGetFileSize path
+
+data Poly_Logging :: E.Effect where
+  Poly_logMsg :: !Text -> Poly_Logging m ()
+
+poly_logMsg :: P.Member Poly_Logging es => String -> P.Sem es ()
+poly_logMsg = P.send . Poly_logMsg . T.pack
+
+poly_runLogging :: P.Sem (Poly_Logging : es) a -> P.Sem es ([Text], a)
+poly_runLogging = P.runState [] . P.reinterpret \case
+  Poly_logMsg msg -> P.modify (msg :)
+
+----------
+
+poly_calculateFileSize
+  :: (P.Member Poly_File es, P.Member Poly_Logging es)
+  => FilePath
+  -> P.Sem es Int
+poly_calculateFileSize path = do
+  poly_logMsg $ "Calculating the size of " ++ path
+  poly_tryFileSize path >>= \case
+    Nothing   -> 0    <$ poly_logMsg ("Could not calculate the size of " ++ path)
+    Just size -> size <$ poly_logMsg (path ++ " is " ++ show size ++ " bytes")
+{-# NOINLINE poly_calculateFileSize #-}
+
+poly_program
+  :: (P.Member Poly_File es, P.Member Poly_Logging es)
+  => [FilePath]
+  -> P.Sem es Int
+poly_program files = do
+  sizes <- traverse poly_calculateFileSize files
+  pure $ sum sizes
+{-# NOINLINE poly_program #-}
+
+poly_calculateFileSizes :: [FilePath] -> IO ([Text], Int)
+poly_calculateFileSizes =
+  P.runM . poly_runFile . poly_runLogging . poly_program
+
+poly_calculateFileSizesDeep :: [FilePath] -> IO ([Text], Int)
+poly_calculateFileSizesDeep = P.runM
+  . runR . runR . runR . runR . runR
+  . poly_runFile . poly_runLogging
+  . runR . runR . runR . runR . runR
+  . poly_program
+  where
+    runR = P.runReader ()
+#endif
diff --git a/bench/BenchLocal.hs b/bench/BenchLocal.hs
--- a/bench/BenchLocal.hs
+++ b/bench/BenchLocal.hs
@@ -1,3 +1,5 @@
+{-# LANGUAGE CPP #-}
+
 -- SPDX-License-Identifier: BSD-3-Clause
 -- (c) 2022 Xy Ren; 2024 Sayo contributors
 
@@ -13,7 +15,9 @@
 import Polysemy qualified as P
 import Polysemy.Reader qualified as P
 import "data-effects" Control.Effect.Interpret qualified as HD
+#ifdef VERSION_eff
 import "eff" Control.Effect qualified as E
+#endif
 
 programHeftia :: (H.Ask Int `H.In` es, H.Local Int `H.In` es) => Int -> H.Eff es Int
 programHeftia = \case
@@ -78,6 +82,7 @@
   where
     run = EL.runReader ()
 
+#ifdef VERSION_eff
 programEff :: (E.Reader Int E.:< es) => Int -> E.Eff es Int
 programEff = \case
     0 -> E.ask
@@ -91,6 +96,7 @@
 localEffDeep n = E.run $ run $ run $ run $ run $ run $ E.runReader @Int 0 $ run $ run $ run $ run $ run $ programEff n
   where
     run = E.runReader ()
+#endif
 
 {-
 The MTL case is disabled because of conflicting functional dependencies.
diff --git a/bench/BenchPyth.hs b/bench/BenchPyth.hs
--- a/bench/BenchPyth.hs
+++ b/bench/BenchPyth.hs
@@ -1,19 +1,22 @@
+{-# LANGUAGE CPP #-}
+
 -- SPDX-License-Identifier: BSD-3-Clause
 -- (c) 2022 Xy Ren; 2024 Sayo contributors
 
 -- Benchmarking yield-intensive code
+
 module BenchPyth where
 
 import Control.Algebra qualified as F
 import Control.Applicative (Alternative (empty, (<|>)))
 import Control.Carrier.NonDet.Church qualified as F
 import Control.Carrier.Reader qualified as F
-import Control.Ev.Eff qualified as E
-import Control.Ev.Util qualified as E
 import Control.Monad (MonadPlus)
+#ifdef VERSION_freer_simple
 import Control.Monad.Freer qualified as FS
 import Control.Monad.Freer.NonDet qualified as FS
 import Control.Monad.Freer.Reader qualified as FS
+#endif
 import Control.Monad.Hefty qualified as H
 import Control.Monad.Hefty.NonDet qualified as H
 import Control.Monad.Hefty.Reader qualified as H
@@ -21,11 +24,12 @@
 import Control.Monad.Identity qualified as M
 import Control.Monad.Logic qualified as M
 import Control.Monad.Reader qualified as M
-import Control.Mp.Eff qualified as Mp
-import Control.Mp.Util qualified as Mp
 import Data.List (singleton)
+#ifdef VERSION_eff
 import "eff" Control.Effect qualified as EF
+#endif
 
+#ifdef VERSION_freer_simple
 programFreer :: (FS.Member FS.NonDet es) => Int -> FS.Eff es (Int, Int, Int)
 programFreer upbound = do
     x <- choice upbound
@@ -44,6 +48,7 @@
 pythFreerDeep n = FS.run $ run $ run $ run $ run $ run $ FS.makeChoiceA $ run $ run $ run $ run $ run $ programFreer n
   where
     run = FS.runReader ()
+#endif
 
 programHeftia :: (H.Choose H.:> es, H.Empty H.:> es) => Int -> H.Eff es (Int, Int, Int)
 programHeftia upbound = do
@@ -93,38 +98,7 @@
   where
     run = F.runReader ()
 
-programEv :: (E.Choose E.:? e) => Int -> E.Eff e (Int, Int, Int)
-programEv upbound = do
-    x <- E.perform E.choose upbound
-    y <- E.perform E.choose upbound
-    z <- E.perform E.choose upbound
-    if x * x + y * y == z * z then return (x, y, z) else E.perform (\r -> E.none r) ()
-{-# NOINLINE programEv #-}
-
-pythEv :: Int -> [(Int, Int, Int)]
-pythEv n = E.runEff $ E.chooseAll $ programEv n
-
-pythEvDeep :: Int -> [(Int, Int, Int)]
-pythEvDeep n = E.runEff $ run $ run $ run $ run $ run $ E.chooseAll $ run $ run $ run $ run $ run $ programEv n
-  where
-    run = E.reader ()
-
-programMp :: (Mp.Choose Mp.:? e) => Int -> Mp.Eff e (Int, Int, Int)
-programMp upbound = do
-    x <- Mp.perform Mp.choose upbound
-    y <- Mp.perform Mp.choose upbound
-    z <- Mp.perform Mp.choose upbound
-    if x * x + y * y == z * z then return (x, y, z) else Mp.perform (\r -> Mp.none r) ()
-{-# NOINLINE programMp #-}
-
-pythMp :: Int -> [(Int, Int, Int)]
-pythMp n = Mp.runEff $ Mp.chooseAll $ programMp n
-
-pythMpDeep :: Int -> [(Int, Int, Int)]
-pythMpDeep n = Mp.runEff $ run $ run $ run $ run $ run $ Mp.chooseAll $ run $ run $ run $ run $ run $ programMp n
-  where
-    run = Mp.reader ()
-
+#ifdef VERSION_eff
 programEff :: (EF.NonDet EF.:< es) => Int -> EF.Eff es (Int, Int, Int)
 programEff upbound = do
     x <- choice upbound
@@ -143,6 +117,7 @@
 pythEffDeep n = EF.run $ run $ run $ run $ run $ run $ EF.runNonDetAll $ run $ run $ run $ run $ run $ programEff n
   where
     run = EF.runReader ()
+#endif
 
 programMtl :: (MonadPlus m) => Int -> m (Int, Int, Int)
 programMtl upbound = do
diff --git a/bench/Main.hs b/bench/Main.hs
--- a/bench/Main.hs
+++ b/bench/Main.hs
@@ -1,5 +1,7 @@
+{-# LANGUAGE CPP #-}
+
 -- SPDX-License-Identifier: BSD-3-Clause
--- (c) 2022 Xy Ren; 2024 Sayo contributors
+-- (c) 2022 Xy Ren; 2021-2022, Andrzej Rybcza; 2024 Sayo contributors
 
 module Main where
 
@@ -10,6 +12,7 @@
 import BenchPyth
 import Data.Functor ((<&>))
 import Test.Tasty.Bench
+import BenchFileSizes
 
 main :: IO ()
 main =
@@ -19,13 +22,16 @@
                 bgroup
                     (show x)
                     [ bench "heftia" $ nf countdownHeftia x
-                    , -- , bench "heftia.naive" $ nf countdownHeftiaNaive x -- no optimization
-                      bench "freer" $ nf countdownFreer x
+                    -- , bench "heftia.naive" $ nf countdownHeftiaNaive x -- no optimization
+#ifdef VERSION_freer_simple
+                    , bench "freer" $ nf countdownFreer x
+#endif
                     , bench "polyemy" $ nf countdownSem x
                     , bench "fused" $ nf countdownFused x
                     , bench "effectful" $ nf countdownEffectful x
+#ifdef VERSION_eff
                     , bench "eff" $ nf countdownEff x
-                    , bench "ev" $ nf countdownEv x
+#endif
                     , bench "mtl" $ nf countdownMtl x
                     ]
         , bgroup "countdown.deep" $
@@ -33,13 +39,16 @@
                 bgroup
                     (show x)
                     [ bench "heftia.5+5" $ nf countdownHeftiaDeep x
-                    , -- , bench "heftia.naive.5+5" $ nf countdownHeftiaNaiveDeep x -- no optimization
-                      bench "freer.5+5" $ nf countdownFreerDeep x
+                    -- , bench "heftia.naive.5+5" $ nf countdownHeftiaNaiveDeep x -- no optimization
+#ifdef VERSION_freer_simple
+                    , bench "freer.5+5" $ nf countdownFreerDeep x
+#endif
                     , bench "polysemy.5+5" $ nf countdownSemDeep x
                     , bench "fused.5+5" $ nf countdownFusedDeep x
                     , bench "effectful.5+5" $ nf countdownEffectfulDeep x
+#ifdef VERSION_eff
                     , bench "eff.5+5" $ nf countdownEffDeep x
-                    , bench "ev.5+5" $ nf countdownEvDeep x
+#endif
                     , bench "mtl.5+5" $ nf countdownMtlDeep x
                     ]
         , bgroup "catch.shallow" $
@@ -103,12 +112,14 @@
                 bgroup
                     (show x)
                     [ bench "heftia" $ nf pythHeftia x
-                    , -- , bench "heftia.shift" $ nf pythHeftiaShift x -- tricky method
-                      bench "freer" $ nf pythFreer x
+                    -- , bench "heftia.shift" $ nf pythHeftiaShift x -- tricky, slow method
+#ifdef VERSION_freer_simple
+                    , bench "freer" $ nf pythFreer x
+#endif
                     , bench "fused" $ nf pythFused x
-                    , bench "ev" $ nf pythEv x
-                    , bench "mp" $ nf pythMp x
+#ifdef VERSION_eff
                     , bench "eff" $ nf pythEff x
+#endif
                     , bench "mtl-logict" $ nf pythLogict x
                     ] -- Polysemy case is excluded because of incorrect semantics.
         , bgroup "nondet.deep" $
@@ -116,12 +127,14 @@
                 bgroup
                     (show x)
                     [ bench "heftia.5+5" $ nf pythHeftiaDeep x
-                    , -- , bench "heftia.shift.5+5" $ nf pythHeftiaShiftDeep x -- tricky method
-                      bench "freer.5+5" $ nf pythFreerDeep x
+                    , bench "heftia.shift.5+5" $ nf pythHeftiaShiftDeep x -- tricky, slow method
+#ifdef VERSION_freer_simple
+                    , bench "freer.5+5" $ nf pythFreerDeep x
+#endif
                     , bench "fused.5+5" $ nf pythFusedDeep x
-                    , bench "ev.5+5" $ nf pythEvDeep x
-                    , bench "mp.5+5" $ nf pythMpDeep x
+#ifdef VERSION_eff
                     , bench "eff.5+5" $ nf pythEffDeep x
+#endif
                     , bench "mtl-logict.5+5" $ nf pythLogictDeep x
                     ]
         , bgroup "coroutine.shallow" $
@@ -129,19 +142,82 @@
                 bgroup
                     (show x)
                     [ bench "heftia" $ nf coroutineHeftia x
+#ifdef VERSION_freer_simple
                     , bench "freer" $ nf coroutineFreer x
+#endif
+#ifdef VERSION_eff
                     , bench "eff" $ nf coroutineEff x
-                    , bench "mp" $ nf coroutineMp x
-                    -- `mpeff` is O(n^2) slow because of: https://dl.acm.org/doi/10.1145/2633357.2633360
-                    -- `eff` is probably for the same reason.
+#endif
+                    -- `eff` is O(n^2) slow probably because of: https://dl.acm.org/doi/10.1145/2633357.2633360
                     ] -- add mtl?
         , bgroup "coroutine.deep" $
             [1000] <&> \x ->
                 bgroup
                     (show x)
                     [ bench "heftia.5+5" $ nf coroutineHeftiaDeep x
+#ifdef VERSION_freer_simple
                     , bench "freer.5+5" $ nf coroutineFreerDeep x
+#endif
+#ifdef VERSION_eff
                     , bench "eff.5+5" $ nf coroutineEffDeep x
-                    , bench "mp.5+5" $ nf coroutineMpDeep x
+#endif
                     ]
+        , bgroup "filesize.shallow" $ map filesizeShallow [1000, 2000, 3000]
+        , bgroup "filesize.deep" $ map filesizeDeep [1000, 2000, 3000]
         ]
+
+filesizeShallow :: Int -> Benchmark
+filesizeShallow n = bgroup (show n)
+  [ bench "reference" $ nfAppIO ref_calculateFileSizes (take n files)
+  , bench "heftia" $ nfAppIO heftia_calculateFileSizes (take n files)
+  , bench "effectful" $ nfAppIO effectful_calculateFileSizes (take n files)
+#ifdef VERSION_cleff
+  , bench "cleff" $ nfAppIO cleff_calculateFileSizes (take n files)
+#endif
+#ifdef VERSION_freer_simple
+  , bench "freer-simple" $ nfAppIO fs_calculateFileSizes (take n files)
+#endif
+#ifdef VERSION_eff
+  , bench "eff" $ nfAppIO eff_calculateFileSizes (take n files)
+#endif
+#ifdef VERSION_mtl
+  , bench "mtl" $ nfAppIO mtl_calculateFileSizes (take n files)
+#endif
+#ifdef VERSION_fused_effects
+  , bench "fused-effects" $ nfAppIO fe_calculateFileSizes (take n files)
+#endif
+#ifdef VERSION_polysemy
+  , bench "polysemy" $ nfAppIO poly_calculateFileSizes (take n files)
+#endif
+  ]
+  where
+    files :: [FilePath]
+    files = repeat "heftia-effects.cabal"
+
+filesizeDeep :: Int -> Benchmark
+filesizeDeep n = bgroup (show n)
+  [ bench "reference" $ nfAppIO ref_calculateFileSizes (take n files)
+  , bench "heftia" $ nfAppIO heftia_calculateFileSizesDeep (take n files)
+  , bench "effectful" $ nfAppIO effectful_calculateFileSizesDeep (take n files)
+#ifdef VERSION_cleff
+  , bench "cleff" $ nfAppIO cleff_calculateFileSizesDeep (take n files)
+#endif
+#ifdef VERSION_freer_simple
+  , bench "freer-simple" $ nfAppIO fs_calculateFileSizesDeep (take n files)
+#endif
+#ifdef VERSION_eff
+  , bench "eff" $ nfAppIO eff_calculateFileSizesDeep (take n files)
+#endif
+#ifdef VERSION_mtl
+  , bench "mtl" $ nfAppIO mtl_calculateFileSizesDeep (take n files)
+#endif
+#ifdef VERSION_fused_effects
+  , bench "fused-effects" $ nfAppIO fe_calculateFileSizesDeep (take n files)
+#endif
+#ifdef VERSION_polysemy
+  , bench "polysemy" $ nfAppIO poly_calculateFileSizesDeep (take n files)
+#endif
+  ]
+  where
+    files :: [FilePath]
+    files = repeat "heftia-effects.cabal"
diff --git a/heftia-effects.cabal b/heftia-effects.cabal
--- a/heftia-effects.cabal
+++ b/heftia-effects.cabal
@@ -1,6 +1,6 @@
 cabal-version:      3.0
 name:               heftia-effects
-version:            0.6.0.1
+version:            0.7.0.0
 
 -- A short (one-line) description of the package.
 synopsis: higher-order algebraic effects done right
@@ -33,7 +33,7 @@
 source-repository head
     type: git
     location: https://github.com/sayo-hs/heftia
-    tag: v0.6.0.1
+    tag: v0.7.0.0
     subdir: heftia-effects
 
 common common-base
@@ -53,12 +53,12 @@
 
     build-depends:
         base >= 4.17 && < 4.22,
-        data-effects ^>= 0.4.0.2,
-        heftia ^>= 0.6,
+        data-effects ^>= 0.4.2,
+        heftia ^>= 0.7,
         time >= 1.11.1 && < 1.15,
         unliftio ^>= 0.2,
         unbounded-delays ^>= 0.1.1,
-        containers > 0.6.5 && < 0.8,
+        containers > 0.6.5 && < 0.9,
         co-log-core ^>= 0.3.2,
         process ^>= 1.6.15,
         bytestring >= 0.11.1 && < 0.13,
@@ -258,11 +258,10 @@
         polysemy ^>= 1.9,
         fused-effects ^>= 1.1,
         effectful >= 2.3 && < 2.6,
-        eveff ^>= 1.0,
         mtl >= 2.2 && < 2.4,
         logict >= 0.7.0.3 && < 0.9,
         tasty-bench >= 0.3 && < 0.5,
-        mpeff,
+        unix,
 
     if impl(ghc >= 9.6) && impl(ghc < 9.10)
        build-depends: eff
@@ -279,3 +278,4 @@
         BenchLocal
         BenchCoroutine
         BenchPyth
+        BenchFileSizes
diff --git a/src/Control/Monad/Hefty/Concurrent/Subprocess.hs b/src/Control/Monad/Hefty/Concurrent/Subprocess.hs
--- a/src/Control/Monad/Hefty/Concurrent/Subprocess.hs
+++ b/src/Control/Monad/Hefty/Concurrent/Subprocess.hs
@@ -25,17 +25,7 @@
 import Control.Applicative ((<|>))
 import Control.Concurrent (forkIO)
 import Control.Monad (liftM2)
-import Control.Monad.Hefty (
-    Eff,
-    Effect,
-    Emb,
-    Freer,
-    interpret,
-    liftIO,
-    makeEffectF,
-    (&),
-    (:>),
- )
+import Control.Monad.Hefty (Eff, Effect, Emb, Freer, RemoveExps, WeakenExps, interpret, liftIO, makeEffectF, (&), (:>))
 import Control.Monad.Hefty.Provider
 import Control.Monad.Hefty.Unlift (UnliftIO, withRunInIO)
 import Data.ByteString (ByteString, hGet, hGetNonBlocking, hPut)
@@ -76,9 +66,12 @@
 deriving stock instance (Show a) => Show (SubprocResult p a)
 deriving stock instance (Eq a) => Eq (SubprocResult p a)
 
-runSubprocIO :: (UnliftIO :> es, Emb IO :> es) => Eff (SubprocProvider es ': es) a -> Eff es a
+runSubprocIO
+    :: (UnliftIO :> es, Emb IO :> es, Emb IO :> RemoveExps es, WeakenExps es)
+    => Eff (SubprocProvider (RemoveExps es) ': es) a
+    -> Eff es a
 runSubprocIO =
-    runScoped \cp@CreateProcess {subprocLifecycle, scopeLifecycle} m ->
+    runRegionScoped @IO \cp@CreateProcess {subprocLifecycle, scopeLifecycle} m ->
         withRunInIO \run -> do
             (hi, ho, he, ph) <- Raw.createProcess (toRawCreateProcess cp) & liftIO
             procStatus <- newEmptyTMVarIO
