diff --git a/ChangeLog.md b/ChangeLog.md
--- a/ChangeLog.md
+++ b/ChangeLog.md
@@ -1,5 +1,11 @@
 # Changelog for polysemy-zoo
+## 0.8.0.0 (2022-03-08)
+### Breaking Changes
+- Removed `Polysemy.IdempotentLowering`, previously deprecated in favor of `Polysemy.Final`.
 
+### Other Changes
+- Updated `asyncToIOFinalGlobal` to support `cancel`.
+
 ## 0.7.0.2 (2020-11-04)
 - Add support for GHC 9.0
   ([#70](https://github.com/polysemy-research/polysemy-zoo/pull/70), thanks to @funketh)
@@ -103,6 +109,3 @@
 ## 0.1.1.0 (2019-05-22)
 
 - Added `Polysemy.IdempotentLowering`
-
-
-## Unreleased changes
diff --git a/polysemy-zoo.cabal b/polysemy-zoo.cabal
--- a/polysemy-zoo.cabal
+++ b/polysemy-zoo.cabal
@@ -1,13 +1,11 @@
-cabal-version: 1.12
+cabal-version: 1.12
 
 -- This file has been generated from package.yaml by hpack version 0.34.4.
 --
 -- see: https://github.com/sol/hpack
---
--- hash: 21ba8ceb18ae6184f65237f20847dd9e3f23ad2838d46fc1cd6af719dac66eb3
 
 name:           polysemy-zoo
-version:        0.7.0.2
+version:        0.8.0.0
 synopsis:       Experimental, user-contributed effects and interpreters for polysemy
 description:    Please see the README on GitHub at <https://github.com/isovector/polysemy-zoo#readme>
 category:       Polysemy
@@ -47,7 +45,6 @@
       Polysemy.Final.NonDet
       Polysemy.Floodgate
       Polysemy.Fresh
-      Polysemy.IdempotentLowering
       Polysemy.Input.Streaming
       Polysemy.KVStore
       Polysemy.Operators
@@ -88,7 +85,7 @@
     , exceptions >=0.10.0 && <0.11
     , ghc-prim >=0.5.2 && <0.8
     , mtl >=2.0.1.0 && <3.0.0.0
-    , polysemy >=1.2.1.0
+    , polysemy >=1.4.0.0
     , random >=1.1 && <1.3
     , reflection >=2.1.4 && <3.0.0
     , streaming ==0.2.*
diff --git a/src/Polysemy/Final/IO.hs b/src/Polysemy/Final/IO.hs
--- a/src/Polysemy/Final/IO.hs
+++ b/src/Polysemy/Final/IO.hs
@@ -32,6 +32,7 @@
     m'  <- runS m
     liftS $ A.async (inspect ins <$> m')
   Await a -> liftS (A.wait a)
+  Cancel a -> liftS (A.cancel a)
 {-# INLINE asyncToIOFinalGlobal #-}
 ------------------------------------------------------------------------------
 -- | 'resourceToIOFinal' implemented using 'interpretFinalGlobal'.
diff --git a/src/Polysemy/IdempotentLowering.hs b/src/Polysemy/IdempotentLowering.hs
deleted file mode 100644
--- a/src/Polysemy/IdempotentLowering.hs
+++ /dev/null
@@ -1,171 +0,0 @@
-{-# LANGUAGE ImpredicativeTypes #-}
--- | =__Unless you absolutely have to use explicit lowering functions, use "Polysemy.Final" instead__
-module Polysemy.IdempotentLowering
-  ( (.@!)
-  , nat
-  , liftNat
-  , fixedNat
-  , (.@@!)
-  , nat'
-  , liftNat'
-  , fixedNat'
-  ) where
-
-import Polysemy
-import Data.Coerce
-
-newtype Nat m n = Nat (∀ x. m x -> n x)
-
-------------------------------------------------------------------------------
--- | This is just 'pure' but with a type specialised for lifting interpreters.
---
--- @since 0.1.1.0
-nat :: Applicative base => (∀ x. m x -> n x) -> base (∀ x. m x -> n x)
-nat f = pure $ coerce $ Nat f
-
-newtype Nat' m n f = Nat' (∀ x. m x -> n (f x))
-
-------------------------------------------------------------------------------
--- | 'nat'' is to 'nat' as '.@@!' is to '.@!'.
---
--- @since 0.1.1.0
-nat' :: Applicative base => (∀ x. m x -> n (f x)) -> base (∀ x. m x -> n (f x))
-nat' f = pure $ coerce $ Nat' f
-
-------------------------------------------------------------------------------
--- | Like 'Polysemy..@', but useful for interpreters that wish to perform some
--- initialization before being run. Most of the time, you don't want to
--- duplicate this initialization every time your effect is lowered.
---
--- Consider an interpreter which wants to use an 'Data.IORef.IORef' to store
--- intermediary state. It might begin like this:
---
--- @
--- myIntepreter
---     :: 'Polysemy.Member' ('Polysemy.Lift' 'IO') r
---     => (∀ x. 'Polysemy.Sem' r x -> 'IO' x)
---     -> 'Polysemy.Sem' (MyEff ': r) a
---     -> 'Polysemy.Sem' r a
--- myInterpreter lower sem = do
---     ref <- 'Polysemy.sendM' $ 'Data.IORef.newIORef' 0
---     go ref sem
---   where
---     go ref = 'Polysemy.interpretH' $ \e -> ...
--- @
---
--- This interpreter will do the wrong thing when composed via 'Polysemy..@'. It
--- would have been correct if we didn't attempt to hide the creation of the
--- 'Data.IORef.IORef', but that's an unfortunate side-effect of wanting to hide
--- implementation details.
---
--- Instead, we can write @myInterpreter@ thusly:
---
--- @
--- myIntepreter
---     :: (∀ x. 'Polysemy.Sem' r x -> 'IO' x)
---     -> 'IO' (∀ a. 'Polysemy.Sem' (MyEff ': r) a -> 'Polysemy.Sem' r a)
--- myInterpreter lower = do
---     ref <- 'Data.IORef.newIORef' 0
---     'nat' $ 'Polysemy.interpretH' $ \e -> ...
--- @
---
--- and use '.@!' (rather than 'Polysemy..@') to compose these things together.
---
--- Note: you must enable @-XImpredicativeTypes@ to give the correct type to
--- @myInterpreter@ here. Don't worry, it's (probably) not as scary as it
--- sounds.
---
--- @since 0.1.1.0
-(.@!)
-    :: (Monad base, Monad m)
-    => base (∀ x. Sem r x -> m x)
-       -- ^ The lowering function, likely @nat runM@.
-    -> ( (∀ x. Sem r x -> m x)
-      -> base ( ∀ y
-           . Sem (e ': r) y
-          -> Sem r y
-           )
-       )
-    -> base (∀ z. Sem (e ': r) z -> m z)
-fi .@! gi = do
-  f <- fi
-  g <- gi (\x -> f x)
-  nat $ \z -> f $ g z
-infixl 8 .@!
-
-
-------------------------------------------------------------------------------
--- | Like '.@!', but for interpreters which change the resulting type --- eg.
--- 'Polysemy.Error.lowerError.
---
--- @since 0.1.1.0
-(.@@!)
-    :: (Monad base, Monad m)
-    => base (∀ x. Sem r x -> m x)
-       -- ^ The lowering function, likely @nat runM@.
-    -> ( (∀ x. Sem r x -> m x)
-      -> base ( ∀ y
-           . Sem (e ': r) y
-          -> Sem r (f y)
-           )
-       )
-    -> base (∀ z. Sem (e ': r) z -> m (f z))
-fi .@@! gi = do
-  f <- fi
-  g <- gi (\x -> f x)
-  nat' $ \z -> f $ g z
-infixl 8 .@@!
-
-
-------------------------------------------------------------------------------
--- | Lift a combinator designed to be used with 'Polysemy..@' into one designed
--- to be used with 'Polysemy..@!'.
-liftNat
-  :: Applicative base
-  => (forall x. (forall y. f y -> g y) -> m x -> n x)
-  -> (forall y. f y -> g y) -> base (forall x. m x -> n x)
-liftNat z a = nat $ z a
-
-------------------------------------------------------------------------------
--- | Lift a combinator designed to be used with 'Polysemy..@@' into one designed
--- to be used with 'Polysemy..@@!'.
-liftNat'
-  :: Applicative base
-  => (forall x. (forall y. f y -> g y) -> m x -> n (f x))
-  -> (forall y. f y -> g y) -> base (forall x. m x -> n (f x))
-liftNat' z a = nat' $ z a
-
-
-------------------------------------------------------------------------------
--- | Like 'nat', but for higher-order interpreters that need access to
--- themselves.
---
--- For example:
---
--- @
--- 'fixedNat' $ \me -> 'Polysemy.interpretH' $ \case
---   SomeEffect -> ...
--- @
-fixedNat
-    :: forall m n base
-     . Applicative base
-    => ((forall x. m x -> n x) -> (forall x. m x -> n x))
-    -> base (forall x. m x -> n x)
-fixedNat f =
-  let x :: (forall x. m x -> n x)
-      x = f x
-   in nat x
-
-
-------------------------------------------------------------------------------
--- | 'fixedNat'' is to 'fixedNat' as 'nat'' is to 'nat'.
-fixedNat'
-    :: forall m n f base
-     . Applicative base
-    => ((forall x. m x -> n (f x)) -> (forall x. m x -> n (f x)))
-    -> base (forall x. m x -> n (f x))
-fixedNat' f =
-  let x :: (forall x. m x -> n (f x))
-      x = f x
-   in nat' x
-
