diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,11 @@
+# effectful-2.2.0.0 (2022-10-24)
+* Change `PrimState` for `Eff` from `RealWorld` to `PrimStateEff` to prevent the
+  `Prim` effect from executing arbitrary `IO` actions via `ioToPrim`.
+* Deprecate `(:>>)` as [GHC can't efficiently deal with type
+  families](https://github.com/haskell-effectful/effectful/issues/52#issuecomment-1269155485).
+* Add support for the `Alternative` and `MonadPlus` instances for `Eff` via the
+  `NonDet` effect.
+
 # effectful-2.1.0.0 (2022-08-22)
 * Include the `e :> localEs` constraint in the `EffectHandler` to allow more
   flexibility in handling higher order effects.
diff --git a/README.md b/README.md
--- a/README.md
+++ b/README.md
@@ -49,19 +49,11 @@
 things that matter instead of reinventing all kinds of wheels, hence being a
 necessary condition for broader adoption of the library.
 
-However, `eff` uses delimited continuations underneath, which:
-
-- Are not yet supported by GHC (though [the
-proposal](https://github.com/ghc-proposals/ghc-proposals/pull/313) for including
-support for them has been accepted).
-
-- Are quite hard to understand.
-
-- Make the library "too powerful" in a sense as it faces
-  [a](https://github.com/hasura/eff/issues/13)
-  [few](https://github.com/hasura/eff/issues/7)
-  [issues](https://github.com/hasura/eff/issues/12) with no clear path towards
-  their resolution.
+Unfortunately, the development of `eff` has stalled due to a
+[few](https://github.com/hasura/eff/issues/13)
+[subtle](https://github.com/hasura/eff/issues/7)
+[issues](https://github.com/hasura/eff/issues/12) related to its use of
+delimited continuations underneath.
 
 ### What about `mtl`?
 
@@ -101,8 +93,19 @@
 
 ### Any downsides?
 
-As always, there's no free lunch. The `Eff` monad doesn't support `NonDet` nor
-`Coroutine` effects. However, the `NonDet` effect in existing libraries is
+As always, there's no free lunch. The `Eff` monad doesn't support effect
+handlers that require the ability to suspend or capture the rest of the
+computation and resume it later (potentially multiple times). This prevents
+`effectful` from providing (in particular):
+
+- A `NonDet` effect handler that executes multiple
+[`Alternative`](https://hackage.haskell.org/package/base/docs/Control-Applicative.html#t:Alternative)
+branches and collects their results.
+
+- A `Coroutine` effect.
+
+It needs to be noted however that such `NonDet` effect handler in existing
+libraries is
 [broken](https://github.com/lexi-lambda/eff/blob/8c4df4bf54faf22456354be18095b14825be5e85/notes/semantics-zoo.md)
 and none of the ones with support for higher order effects provide the
 `Coroutine` effect, so arguably it's not a big loss.
@@ -110,7 +113,7 @@
 If you need such capability in your application, there are well established
 libraries such as [conduit](https://hackage.haskell.org/package/conduit) or
 [list-t](https://hackage.haskell.org/package/list-t) that can be used with
-`effectful` without any issues.
+`effectful` without any hassle.
 
 ### Summary
 
@@ -147,9 +150,10 @@
 
 ## Example
 
-A `Filesystem` effect with two handlers, one that runs in `IO` and another that
-uses an in-memory virtual file system can be found
-[here](https://github.com/haskell-effectful/effectful/blob/master/effectful/examples/FileSystem.hs).
+For the examples see the *Introduction* sections of
+[`Effectful.Dispatch.Dynamic`](https://hackage.haskell.org/package/effectful-core/docs/Effectful-Dispatch-Dynamic.html)
+and
+[`Effectful.Dispatch.Static`](https://hackage.haskell.org/package/effectful-core/docs/Effectful-Dispatch-Static.html).
 
 ## Resources
 
diff --git a/effectful.cabal b/effectful.cabal
--- a/effectful.cabal
+++ b/effectful.cabal
@@ -1,7 +1,7 @@
 cabal-version:      2.4
 build-type:         Simple
 name:               effectful
-version:            2.1.0.0
+version:            2.2.0.0
 license:            BSD-3-Clause
 license-file:       LICENSE
 category:           Control
@@ -22,7 +22,7 @@
   CHANGELOG.md
   README.md
 
-tested-with: GHC ==8.8.4 || ==8.10.7 || ==9.0.2 || ==9.2.4 || ==9.4.1
+tested-with: GHC ==8.8.4 || ==8.10.7 || ==9.0.2 || ==9.2.4 || ==9.4.2
 
 bug-reports:   https://github.com/haskell-effectful/effectful/issues
 source-repository head
@@ -67,7 +67,7 @@
                     , async               >= 2.2.2
                     , bytestring          >= 0.10
                     , directory           >= 1.3.2
-                    , effectful-core      >= 2.1.0.0   && < 2.1.1.0
+                    , effectful-core      >= 2.2.0.0   && < 2.2.1.0
                     , process             >= 1.6.9
 
                     , time                >= 1.9.2
@@ -101,6 +101,7 @@
                          , Effectful.Error.Static
                          , Effectful.Error.Dynamic
                          , Effectful.Fail
+                         , Effectful.NonDet
                          , Effectful.Prim
                          , Effectful.Reader.Dynamic
                          , Effectful.Reader.Static
@@ -122,11 +123,12 @@
                     , effectful-core
                     , exceptions
                     , lifted-base
+                    , primitive
                     , tasty
                     , tasty-hunit
                     , unliftio
 
-    hs-source-dirs: tests examples
+    hs-source-dirs: tests
 
     type:           exitcode-stdio-1.0
     main-is:        Main.hs
@@ -136,14 +138,13 @@
                     EnvTests
                     EnvironmentTests
                     ErrorTests
+                    NonDetTests
+                    PrimTests
                     ReaderTests
                     StateTests
                     TimeoutTests
                     UnliftTests
                     Utils
-                    -- These are examples; We do not actually run them but list
-                    -- them here in order to check if they compile.
-                    FileSystem
 
 benchmark bench
     import:         language
diff --git a/examples/FileSystem.hs b/examples/FileSystem.hs
deleted file mode 100644
--- a/examples/FileSystem.hs
+++ /dev/null
@@ -1,64 +0,0 @@
-module FileSystem
-  ( FileSystem(..)
-  , FsError(..)
-  , readFile
-  , writeFile
-  , runFileSystemIO
-  , runFileSystemPure
-  ) where
-
-import Control.Exception (IOException)
-import Control.Monad.Catch
-import Prelude hiding (readFile, writeFile)
-import qualified Data.Map.Strict as M
-import qualified System.IO as IO
-
-import Effectful
-import Effectful.Dispatch.Dynamic
-import Effectful.Error.Static
-import Effectful.State.Static.Local
-
--- | An effect for reading and writing files.
-data FileSystem :: Effect where
-  ReadFile  :: FilePath -> FileSystem m String
-  WriteFile :: FilePath -> String -> FileSystem m ()
-
-type instance DispatchOf FileSystem = Dynamic
-
---- | File system error.
-newtype FsError = FsError String
-
-----------------------------------------
--- Operations
-
--- | Read contents of a file.
-readFile :: (HasCallStack, FileSystem :> es) => FilePath -> Eff es String
-readFile = send . ReadFile
-
--- | Write contents to a file.
-writeFile :: (HasCallStack, FileSystem :> es) => FilePath -> String -> Eff es ()
-writeFile path = send . WriteFile path
-
-----------------------------------------
--- Handlers
-
-runFileSystemIO
-  :: (IOE :> es, Error FsError :> es)
-  => Eff (FileSystem : es) a
-  -> Eff es a
-runFileSystemIO = interpret $ \_ -> \case
-  ReadFile path           -> adapt $ IO.readFile path
-  WriteFile path contents -> adapt $ IO.writeFile path contents
-  where
-    adapt m = liftIO m `catch` \(e::IOException) -> throwError . FsError $ show e
-
-runFileSystemPure
-  :: Error FsError :> es
-  => M.Map FilePath String
-  -> Eff (FileSystem : es) a
-  -> Eff es a
-runFileSystemPure fs0 = reinterpret (evalState fs0) $ \_ -> \case
-  ReadFile path -> gets (M.lookup path) >>= \case
-    Just contents -> pure contents
-    Nothing       -> throwError . FsError $ "File not found: " ++ show path
-  WriteFile path contents -> modify $ M.insert path contents
diff --git a/tests/EnvTests.hs b/tests/EnvTests.hs
--- a/tests/EnvTests.hs
+++ b/tests/EnvTests.hs
@@ -7,6 +7,8 @@
 
 import Effectful
 import Effectful.Dispatch.Dynamic
+import Effectful.Dispatch.Static
+import Effectful.Dispatch.Static.Primitive
 import Effectful.Reader.Static
 import Effectful.State.Static.Local
 import qualified Utils as U
@@ -60,11 +62,13 @@
 
 test_noUnsafeCoerce :: Assertion
 test_noUnsafeCoerce = do
-  r <- try @ErrorCall . evaluate $ unsafeCoerce @Int 'a'
-  assertBool "unsafeCoerce" (isLeft r)
+  r1 <- try @ErrorCall . evaluate $ unsafeCoerce1 @Int 'a'
+  assertBool "unsafeCoerce1" (isLeft r1)
+  r2 <- try @ErrorCall . evaluate $ unsafeCoerce2 @Int 'a'
+  assertBool "unsafeCoerce2" (isLeft r2)
 
-unsafeCoerce :: forall b a. a -> b
-unsafeCoerce a = runPureEff $ do
+unsafeCoerce1 :: forall b a. a -> b
+unsafeCoerce1 a = runPureEff $ do
   -- 'oops' gains access to the effect stack with Reader (Box b) via the
   -- unlifting function that escaped its scope. The problem here is that this
   -- effect is no longer in scope.
@@ -72,7 +76,27 @@
     raiseWith SeqUnlift $ \unlift -> do
       pure . unlift $ ask @(Box b)
   -- Put Reader (Box a) where the Reader (Box b) was before and attempt to
-  -- retrieve 'a' coerced to 'b'. It fails because 'getLocation' in
+  -- retrieve 'a' coerced to 'b'. It should fail because 'getLocation' in
+  -- 'Effectful.Internal.Env' checks that version of the reference is the same
+  -- as version of the effect.
+  Box b <- runReader (Box a) $ raise oops
+  pure b
+
+unsafeCoerce2 :: forall b a. a -> b
+unsafeCoerce2 a = runPureEff $ do
+  backupEs <- unsafeEff cloneEnv
+  -- 'oops' gains access to the effect stack with Reader (Box b) via the
+  -- unlifting function that escaped its scope. The problem here is that this
+  -- effect is no longer in scope.
+  oops <- runReader @(Box b) (Box undefined) $ do
+    raiseWith SeqUnlift $ \unlift -> do
+      pure . unlift $ ask @(Box b)
+  -- If restoreEnv messes up versioning (i.e. restores the version counter from
+  -- before the above Reader was used), below code will succeed because the
+  -- Reader (Box a) will have the same version as Reader (Box b).
+  unsafeEff $ \es -> restoreEnv es backupEs
+  -- Put Reader (Box a) where the Reader (Box b) was before and attempt to
+  -- retrieve 'a' coerced to 'b'. It should fail because 'getLocation' in
   -- 'Effectful.Internal.Env' checks that version of the reference is the same
   -- as version of the effect.
   Box b <- runReader (Box a) $ raise oops
diff --git a/tests/ErrorTests.hs b/tests/ErrorTests.hs
--- a/tests/ErrorTests.hs
+++ b/tests/ErrorTests.hs
@@ -9,29 +9,29 @@
 
 errorTests :: TestTree
 errorTests = testGroup "Error"
-  [ testCase "error from interpret" test_errorFromInterpret
+  [ testCase "different handlers are independent" test_independentHandlers
   ]
 
-test_errorFromInterpret :: Assertion
-test_errorFromInterpret = runEff $ do
-  result <- runError @String . runNestedErr $ do
-    runError @String nestedErr
+test_independentHandlers :: Assertion
+test_independentHandlers = runEff $ do
+  result <- runError @String . runOuterThrow $ do
+    runError @String outerThrow
   liftIO $ case result of
     Left (cs, _) -> assertBool "stack trace points to the correct action" $
-      "nestedErr" == fst (last $ getCallStack cs)
+      "outerThrow" == fst (last $ getCallStack cs)
     Right _ -> assertFailure "error caught by the wrong (inner) handler"
 
 ----------------------------------------
 -- Helpers
 
-data NestedErr :: Effect where
-  NestedErr :: NestedErr m ()
+data OuterThrow :: Effect where
+  OuterThrow :: OuterThrow m ()
 
-type instance DispatchOf NestedErr = Dynamic
+type instance DispatchOf OuterThrow = Dynamic
 
-nestedErr :: (HasCallStack, NestedErr :> es) => Eff es ()
-nestedErr = send NestedErr
+outerThrow :: (HasCallStack, OuterThrow :> es) => Eff es ()
+outerThrow = send OuterThrow
 
-runNestedErr :: Error String :> es => Eff (NestedErr : es) a -> Eff es a
-runNestedErr = interpret $ \_ -> \case
-  NestedErr -> throwError "nested error"
+runOuterThrow :: Error String :> es => Eff (OuterThrow : es) a -> Eff es a
+runOuterThrow = interpret $ \_ -> \case
+  OuterThrow -> throwError "outer"
diff --git a/tests/Main.hs b/tests/Main.hs
--- a/tests/Main.hs
+++ b/tests/Main.hs
@@ -7,6 +7,8 @@
 import EnvTests
 import EnvironmentTests
 import ErrorTests
+import NonDetTests
+import PrimTests
 import ReaderTests
 import StateTests
 import TimeoutTests
@@ -19,6 +21,8 @@
   , envTests
   , environmentTests
   , errorTests
+  , nonDetTests
+  , primTests
   , readerTests
   , stateTests
   , timeoutTests
diff --git a/tests/NonDetTests.hs b/tests/NonDetTests.hs
new file mode 100644
--- /dev/null
+++ b/tests/NonDetTests.hs
@@ -0,0 +1,101 @@
+module NonDetTests (nonDetTests) where
+
+import Test.Tasty
+import Test.Tasty.HUnit
+
+import Effectful
+import Effectful.Dispatch.Dynamic
+import Effectful.NonDet
+import Effectful.Reader.Static
+import Effectful.State.Dynamic
+
+import qualified Utils as U
+
+nonDetTests :: TestTree
+nonDetTests = testGroup "NonDet"
+  [ testCaseSteps "empty (left)"  $ test_empty leftEmpty
+  , testCaseSteps "empty (right)" $ test_empty rightEmpty
+  , testGroup "interaction"
+    [ testCaseSteps "local state"  $ test_state evalStateLocal  expectedLocalState
+    , testCaseSteps "shared state" $ test_state evalStateShared expectedSharedState
+    ]
+  , testCaseSteps "different handlers are independent" test_independentHandlers
+  ]
+  where
+    leftEmpty :: NonDet :> es => Eff es Bool
+    leftEmpty  = runReader () (empty >> pure False) <|> runReader () (pure True)
+
+    rightEmpty :: NonDet :> es => Eff es Bool
+    rightEmpty = runReader () (pure True) <|> runReader () (empty >> pure False)
+
+    expectedLocalState :: OnEmptyPolicy -> Int
+    expectedLocalState = \case
+      OnEmptyKeep     -> 3
+      OnEmptyRollback -> 2
+
+    expectedSharedState :: OnEmptyPolicy -> Int
+    expectedSharedState _ = 3
+
+test_empty
+  :: Eff [NonDet, IOE] Bool
+  -> (String -> IO ())
+  -> Assertion
+test_empty test step = runEff $ do
+  runNonDetBoth test $ \policy result -> do
+    liftIO . step $ show policy
+    U.assertEqual "result" (Just True) (dropLeft result)
+
+test_state
+  :: (forall r. Int -> Eff [State Int, IOE] r -> Eff '[IOE] r)
+  -> (OnEmptyPolicy -> Int)
+  -> (String -> IO ())
+  -> IO ()
+test_state evalState expectedState step = runEff $ do
+  evalState 0 . runNonDetBoth test $ \policy result -> do
+    liftIO . step $ show policy
+    U.assertEqual "result" (Just ()) (dropLeft result)
+    s <- state @Int $ \s -> (s, 0)
+    U.assertEqual "state" (expectedState policy) s
+  where
+    test :: (NonDet :> es, State Int :> es) => Eff es ()
+    test = (modify @Int (+1) >> empty) <|> modify @Int (+2)
+
+test_independentHandlers :: (String -> IO ()) -> Assertion
+test_independentHandlers step = runEff $ do
+  runNonDetBoth test $ \policy result -> liftIO $ do
+    step $ show policy
+    case result of
+      Left cs -> assertBool "stack trace points to the correct action" $
+        "outerEmpty" == fst (last $ getCallStack cs)
+      Right _ -> assertFailure "empty handled by the wrong (inner) handler"
+  where
+    test :: NonDet :> es => Eff es (Either CallStack Bool)
+    test = runOuterEmpty . runNonDet OnEmptyKeep $ outerEmpty <|> pure True
+
+----------------------------------------
+-- Helpers
+
+data OuterEmpty :: Effect where
+  OuterEmpty :: OuterEmpty m a
+
+type instance DispatchOf OuterEmpty = Dynamic
+
+outerEmpty :: (HasCallStack, OuterEmpty :> es) => Eff es a
+outerEmpty = send OuterEmpty
+
+runOuterEmpty :: NonDet :> es => Eff (OuterEmpty : es) a -> Eff es a
+runOuterEmpty = interpret $ \_ -> \case
+  OuterEmpty -> emptyEff
+
+----
+
+dropLeft :: Either e a -> Maybe a
+dropLeft = either (const Nothing) Just
+
+runNonDetBoth
+  :: Eff (NonDet : es) a
+  -> (OnEmptyPolicy -> Either CallStack a -> Eff es ())
+  -> Eff es ()
+runNonDetBoth m k = do
+  k OnEmptyKeep     =<< runNonDet OnEmptyKeep m
+  k OnEmptyRollback =<< runNonDet OnEmptyRollback m
diff --git a/tests/PrimTests.hs b/tests/PrimTests.hs
new file mode 100644
--- /dev/null
+++ b/tests/PrimTests.hs
@@ -0,0 +1,22 @@
+module PrimTests (primTests) where
+
+import Data.Primitive.MutVar
+import Test.Tasty
+import Test.Tasty.HUnit
+import qualified Utils as U
+
+import Effectful
+import Effectful.Prim
+
+primTests :: TestTree
+primTests = testGroup "Prim"
+  [ testCase "MutVar works" test_MutVar
+  ]
+
+test_MutVar :: Assertion
+test_MutVar = runEff . runPrim $ do
+  mv <- newMutVar (0::Int)
+  modifyMutVar mv (+1)
+  v <- readMutVar mv
+  writeMutVar mv (v + 2)
+  U.assertEqual "MutVar works" 3 =<< readMutVar mv
diff --git a/tests/ReaderTests.hs b/tests/ReaderTests.hs
--- a/tests/ReaderTests.hs
+++ b/tests/ReaderTests.hs
@@ -25,7 +25,7 @@
 test_localInHandler runR = runEff . runR "global" . interpret f $ do
   local (const "local") $ send SomeAction
   where
-    f :: [IOE, Reader String] :>> es => EffectHandler SomeEff es
+    f :: (IOE :> es, Reader String :> es) => EffectHandler SomeEff es
     f _ SomeAction = U.assertEqual "expected result" "local" =<< ask
 
 -- | Purely dynamic Reader for testing purposes.
