diff --git a/CHANGES.markdown b/CHANGES.markdown
--- a/CHANGES.markdown
+++ b/CHANGES.markdown
@@ -1,7 +1,87 @@
+## Changes in 0.15.0 [2026.01.10]
+ - Sync with `base-4.22`/GHC 9.14
+ - Restrict `Data.List.NonEmpty.Compat.unzip` to be of type
+   `NonEmpty (a, b) -> (NonEmpty a, NonEmpty b)`, mirroring similar changes
+   introducted in `base-4.22`.
+
+## Changes in 0.14.1 [2024.12.06]
+ - Sync with `base-4.21`/GHC 9.12
+ - Backport `compareLength` to `Data.List.Compat` and
+   `Data.List.NonEmpty.Compat`
+ - Backport `inits1` and `tails1` to `Data.List.Compat`
+ - Backport `firstA` and `secondA` to `Data.Bitraversable.Compat`
+ - Drop support for pre-8.0 versions of GHC.
+
+## Changes in 0.14.0 [2024.04.30]
+ - Sync with `base-4.20`/GHC 9.10
+ - Backport `foldl'` to `Prelude.Compat`
+ - Backport `List` to `Data.List.Compat` (when building with GHC 9.6 or later)
+ - Backport `append`, `appendList`, `prependList`, `permutations`,
+   `permutations1`, and `sortOn` to `Data.List.NonEmpty.Compat` (when building
+   with GHC 8.0 or later)
+
+## Changes in 0.13.1 [2023.10.11]
+ - Sync with `base-4.19`/GHC 9.8
+ - Backport `unzip` to `Data.Functor.Compat`
+ - Backport `(!?)` and `unsnoc` to `Data.List.Compat`
+ - Backport `getSolo` to `Data.Tuple.Compat` when building against
+   `ghc-prim-0.8.0` (GHC 9.2) or later. To backport `getSolo` to older versions
+   of GHC, import `Data.Tuple.Compat` from `base-compat-batteries` instead.
+ - Backport `decT` and `hdecT` to `Data.Typeable.Compat`
+ - Backport `decTypeRep` to `Type.Reflection.Compat`
+
+## Changes in 0.13.0 [2023.03.10]
+ - Sync with `base-4.18`/GHC 9.6
+ - Backport `liftA2` being re-exported from `Prelude.Compat`.
+ - `Data.Tuple.Compat`'s `Solo` API now matches what is present in `Data.Tuple`
+   in `base-4.18`. In particular, we now re-export both the `MkSolo` and `Solo`
+   data constructors when building with `ghc-prim-0.10.0` or later, with
+   `MkSolo` being preferred over `Solo`. If you want to backport `MkSolo` to
+   earlier versions of GHC, import `Data.Tuple.Compat` from
+   `base-compat-batteries` instead.
+ - Backport `traceWith`, `traceShowWith`, and `traceEventWith` to `Debug.Trace`.
+   Note that `traceEventWith` is only provided when building with `base-4.5` or
+   later, as that is the first version of `base` to provide the `traceEvent`
+   primitive on which `traceEventWith` is defined.
+ - Backport `inits1` and `tails1` to `Data.List.NonEmpty.Compat`.
+ - Backport `minusNaturalMaybe` to `Numeric.Natural.Compat`.
+ - Backport `applyWhen` to `Data.Function.Compat`.
+ - Backport `mapAccumM` and `forAccumM` to `Data.Traversable.Compat`.
+ - Backport `heqT` to `Data.Typeable.Compat`. Note that `heqT` is only defined
+   when building with `base-4.10` or later, as that is the first version of
+   `base` to provide the primitives needed to define `heqT`.
+ - Introduce `Data.Foldable1.Compat` and `Data.Bifoldable1.Compat` modules,
+   which correspond to changes made in `base-4.18.0.0`. You may consider using
+   `base-compat-batteries` instead if you want increase the range of `base`
+   versions that are supported.
+
+## Changes in 0.12.3 [2023.07.12]
+ - This coincides with the `base-compat-batteries-0.12.3` release. Refer to the
+   [`base-compat-batteries` changelog](https://github.com/haskell-compat/base-compat/blob/master/base-compat-batteries/CHANGES.markdown#changes-in-0123-20230712)
+   for more details.
+
+## Changes in 0.12.2 [2022.08.11]
+ - Sync with `base-4.17`/GHC 9.4
+ - Backport `(.^.)`, `(.>>.)`, `(.<<.)`, `(!>>.)`, `(!<<.)`, `oneBits` to
+   `Data.Bits.Compat`
+ - Backport `pattern TypeRep` to `Type.Reflection.Compat`
+
+## Changes in 0.12.1 [2021.10.30]
+ - Backport `Solo` to `Data.Tuple.Compat` when building with `ghc-prim-0.7.0`
+   or later
+
+## Changes in 0.12.0 [2021.08.29]
+ - Sync with `base-4.16`/GHC 9.2
+ - `Data.Semigroup.Compat{.Repl}` no longer re-exports the `Option` data type
+   or the `option` function, as both have been removed in `base-4.16`.
+ - Backport `readBin` and `showBin` to `Numeric.Compat`
+ - Backport `readBinP` to `Text.Read.Lex.Compat`
+
 ## Changes in 0.11.2 [2020.09.30]
  - Sync with `base-4.15`/GHC 9.0
- - Backport `singleton` to `Data.List` and `Data.List.NonEmpty`
- - Backport `hGetContents'`, `getContents'`, and `readFile'` added to `System.IO`
+ - Backport `singleton` to `Data.List.Compat` and `Data.List.NonEmpty.Compat`
+ - Backport `hGetContents'`, `getContents'`, and `readFile'` added to
+   `System.IO.Compat`
 
 ## Changes in 0.11.1 [2020.01.27]
  - Sync with `base-4.14`/GHC 8.10
diff --git a/README.markdown b/README.markdown
--- a/README.markdown
+++ b/README.markdown
@@ -117,8 +117,10 @@
  * `Text.Read.Compat.readMaybe`
  * `Text.Read.Compat.readEither`
  * `Data.Monoid.Compat.<>`
- * Added `bitDefault`, `testBitDefault`, and `popCountDefault` to `Data.Bits.Compat`
- * Added `toIntegralSized` to `Data.Bits.Compat` (if using `base-4.7`)
+ * Added `bitDefault`, `testBitDefault`, `popCountDefault`, `(.^.)`, `(.>>.)`,
+   `(.<<.)`, `(!>>.)`, and `(!<<.)` to `Data.Bits.Compat`
+ * Added `toIntegralSized` and `oneBits` to `Data.Bits.Compat` (if using `base-4.7` or later)
+ * Added `firstA` and `secondA` to `Data.Bitraversable.Compat`
  * Added `bool` function to `Data.Bool.Compat`
  * Added `isLeft`, `isRight`, `fromLeft`, and `fromRight` to `Data.Either.Compat`
  * Added `forkFinally` to `Control.Concurrent.Compat`
@@ -128,32 +130,51 @@
    and `cis` in `Data.Complex.Compat`
  * Added more efficient `maximumBy`/`minimumBy` to `Data.Foldable.Compat`
  * Added `($>)` and `void` functions to `Data.Functor.Compat`
- * `(&)` function to `Data.Function.Compat`
+ * `(&)` and `applyWhen` functions to `Data.Function.Compat`
  * `($>)` and `void` functions to `Data.Functor.Compat`
  * `modifyIORef'`, `atomicModifyIORef'` and `atomicWriteIORef` to `Data.IORef.Compat`
  * `dropWhileEnd`, `isSubsequenceOf`, `sortOn`, and `uncons` functions to `Data.List.Compat`
  * Correct versions of `nub`, `nubBy`, `union`, and `unionBy` to `Data.List.Compat`
+ * `inits1` and `tails1` to `Data.List.Compat`
+ * `compareLength` to `Data.List.Compat` and `Data.List.NonEmpty.Compat`
  * `asProxyTypeOf` with a generalized type signature to `Data.Proxy.Compat`
  * `modifySTRef'` to `Data.STRef.Compat`
  * `String`, `lines`, `words`, `unlines`, and `unwords` to `Data.String.Compat`
  * `gcoerceWith` to `Data.Type.Coercion.Compat`
  * `makeVersion` function to `Data.Version.Compat`
- * `traceId`, `traceShowId`, `traceM`, and `traceShowM` functions to `Debug.Trace.Compat`
+ * `traceId`, `traceShowId`, `traceM`, `traceShowM`, `traceWith`,
+   `traceShowWith`, and `traceEventWith` functions to `Debug.Trace.Compat`
  * `byteSwap16`, `byteSwap32`, and `byteSwap64` to `Data.Word.Compat`
  * `plusForeignPtr` to `Foreign.ForeignPtr.Compat`
  * `calloc` and `callocBytes` functions to `Foreign.Marshal.Alloc.Compat`
  * `callocArray` and `callocArray0` functions to `Foreign.Marshal.Array.Compat`
  * `fillBytes` to `Foreign.Marshal.Utils.Compat`
  * Added `Data.List.Compat.scanl'`
- * `showFFloatAlt` and `showGFloatAlt` to `Numeric.Compat`
+ * `showFFloatAlt`, `showGFloatAlt`, `readBin`, and `showBin` to `Numeric.Compat`
  * `lookupEnv`, `setEnv` and `unsetEnv` to `System.Environment.Compat`
  * `unsafeFixIO` and `unsafeDupablePerformIO` to `System.IO.Unsafe.IO`
  * `RuntimeRep`-polymorphic `($!)` to `Prelude.Compat`
+ * `liftA2` is re-exported from `Prelude.Compat`
+ * `foldl'` is re-exported from `Prelude.Compat`
  * `RuntimeRep`-polymorphic `throw` to `Control.Exception.Compat`
  * `isResourceVanishedError`, `resourceVanishedErrorType`, and
    `isResourceVanishedErrorType` to `System.IO.Error.Compat`
  * `singleton` to `Data.List.Compat` and `Data.List.NonEmpty.Compat`
- * `hGetContents'`, `getContents'`, and `readFile'` to `System.IO`
+ * `inits1` and `tails1` to `Data.List.NonEmpty.Compat`
+ * `permutations`, `permutations1`, and `sortOn` to `Data.List.NonEmpty.Compat`
+ * `Data.List.NonEmpty.Compat`'s `unzip` function is restricted to only work over `NonEmpty` lists
+ * `hGetContents'`, `getContents'`, and `readFile'` to `System.IO.Compat`
+ * `readBinP` to `Text.Read.Lex.Compat`
+ * `withTypeable` and `pattern TypeRep` to `Type.Reflection.Compat`
+ * `minusNaturalMaybe` to `Numeric.Natural.Compat`
+ * `mapAccumM` and `forAccumM` to `Data.Traversable.Compat`
+ * `heqT` to `Data.Typeable.Compat`
+ * `unzip` to `Data.Functor.Compat`
+ * `(!?)` and `unsnoc` to `Data.List.Compat`
+ * `List` to `Data.List.Compat` (when building with GHC 9.6 or later)
+ * `getSolo` to `Data.Tuple.Compat`
+ * `decT` and `hdecT` to `Data.Typeable.Compat`
+ * `decTypeRep` to `Type.Reflection.Compat`
 
 ## What is not covered
 
@@ -257,55 +278,50 @@
 Here is a list of compatibility libraries that `base-compat-batteries` depends
 on, paired with the things that each library backports:
 
-* [`bifunctors`](http://hackage.haskell.org/package/bifunctors)
-  for:
-  * The [`Bifunctor`](http://hackage.haskell.org/package/base-4.8.0.0/docs/Data-Bifunctor.html#t:Bifunctor)
-    type class, introduced in `base-4.8.0.0`
-  * The [`Bifoldable`](http://hackage.haskell.org/package/base-4.10.0.0/docs/Data-Bifoldable.html#t:Bifoldable)
-    and [`Bitraversable`](http://hackage.haskell.org/package/base-4.10.0.0/docs/Data-Bitraversable.html#t:Bitraversable)
-    type classes, introduced in `base-4.10.0.0`
+* [`bifunctor-classes-compat`](http://hackage.haskell.org/package/bifunctor-classes-compat)
+  for the
+  [`Bifoldable`](http://hackage.haskell.org/package/base-4.10.0.0/docs/Data-Bifoldable.html#t:Bifoldable)
+  and
+  [`Bitraversable`](http://hackage.haskell.org/package/base-4.10.0.0/docs/Data-Bitraversable.html#t:Bitraversable)
+  type classes, introduced in `base-4.10.0.0`
 * [`contravariant`](http://hackage.haskell.org/package/contravariant)
   for the [`Contravariant`](http://hackage.haskell.org/package/base-4.12.0.0/docs/Data-Functor-Contravariant.html#t:Contravariant)
   type class, introduced in `base-4.12.0.0`.
-* [`fail`](http://hackage.haskell.org/package/fail)
-  for the [`MonadFail`](http://hackage.haskell.org/package/base-4.9.0.0/docs/Control-Monad-Fail.html#t:MonadFail)
-  type class, introduced in `base-4.9.0.0`
-* [`nats`](http://hackage.haskell.org/package/nats)
-  for the [`Natural`](http://hackage.haskell.org/package/base-4.8.0.0/docs/Numeric-Natural.html)
-  data type, introduced in `base-4.8.0.0`
-* [`semigroups`](http://hackage.haskell.org/package/semigroups)
-  for the [`Semigroup`](http://hackage.haskell.org/package/base-4.9.0.0/docs/Data-Semigroup.html#t:Semigroup)
-  typeclass and the
-  [`NonEmpty`](http://hackage.haskell.org/package/base-4.9.0.0/docs/Data-List-NonEmpty.html#t:NonEmpty),
-  [`Min`](http://hackage.haskell.org/package/base-4.9.0.0/docs/Data-Semigroup.html#t:Min),
-  [`Max`](http://hackage.haskell.org/package/base-4.9.0.0/docs/Data-Semigroup.html#t:Max),
-  [`First`](http://hackage.haskell.org/package/base-4.9.0.0/docs/Data-Semigroup.html#t:First),
-  [`Last`](http://hackage.haskell.org/package/base-4.9.0.0/docs/Data-Semigroup.html#t:Last),
-  [`WrappedMonoid`](http://hackage.haskell.org/package/base-4.9.0.0/docs/Data-Semigroup.html#t:WrappedMonoid),
-  [`Option`](http://hackage.haskell.org/package/base-4.9.0.0/docs/Data-Semigroup.html#t:Option),
-  and
-  [`Arg`](http://hackage.haskell.org/package/base-4.9.0.0/docs/Data-Semigroup.html#t:Arg)
-  data types, introduced in `base-4.9.0.0`
-* [`tagged`](http://hackage.haskell.org/package/tagged)
-  for the [`Proxy`](http://hackage.haskell.org/package/base-4.7.0.0/docs/Data-Proxy.html#t:Proxy)
-  data type, introduced in `base-4.7.0.0`
-* [`transformers`](http://hackage.haskell.org/package/transformers)
-  for:
-  * The [`Identity`](http://hackage.haskell.org/package/base-4.8.0.0/docs/Data-Functor-Identity.html#t:Identity)
-    data type, introduced in `base-4.8.0.0`
-  * The [`MonadIO`](http://hackage.haskell.org/package/base-4.9.0.0/docs/Control-Monad-IO-Class.html#t:MonadIO)
-    type class; and the
-    [`Compose`](http://hackage.haskell.org/package/base-4.9.0.0/docs/Data-Functor-Compose.html#t:Compose),
-    [`Product`](http://hackage.haskell.org/package/base-4.9.0.0/docs/Data-Functor-Product.html#t:Product),
-    and
-    [`Sum`](http://hackage.haskell.org/package/base-4.9.0.0/docs/Data-Functor-Sum.html#t:Sum)
-    data types, introduced in `base-4.9.0.0`
-* [`void`](http://hackage.haskell.org/package/void)
-  for the [`Void`](http://hackage.haskell.org/package/base-4.8.0.0/docs/Data-Void.html#t:Void)
-  data type, introduced in `base-4.8.0.0`
+* [`foldable1-classes-compat`](https://hackage.haskell.org/package/foldable1-classes-compat)
+  for the [`Foldable1`](https://hackage.haskell.org/package/foldable1-classes-compat-0.1/docs/Data-Foldable1.html#t:Foldable1)
+  and [`Bifoldable1`](https://hackage.haskell.org/package/foldable1-classes-compat-0.1/docs/Data-Bifoldable1.html#t:Bifoldable1)
+  type classes, introduced in `base-4.18.0.0`
+* [`OneTuple`](http://hackage.haskell.org/package/OneTuple)
+  for the [`Solo`](https://hackage.haskell.org/package/base-4.16.0.0/docs/Data-Tuple.html#t:Solo)
+  data type, introduced in `ghc-prim-0.7.0`
 
+## Version policy
+
+This package follows the [Haskell Package Versioning
+Policy](https://pvp.haskell.org/). As such, if a new `base-compat` release only
+adds new exports, then as a general rule, we will release it with a minor
+version bump. Moreover, since `base-compat` does not backport data type or
+class definitions (see the "What is not covered" section above), `base-compat`
+usually has fewer major version bumps than `base` itself.
+
+An exception to the general rule about adding new exports is the
+`Prelude.Compat` module. If a new `base-compat` release adds any new exports,
+then it will _always_ be accompanied by a major version bump, even if there are
+no other API changes. This is because of the special nature of
+`Prelude.Compat`, which is designed to be imported unqualified. Pre-emptively
+bumping the major version number is meant to signal to downstream libraries
+that they should check to see if the new `Prelude.Compat` additions will clash
+with identifiers of the same names in their code.
+
 ## Supported versions of GHC/`base`
 
+ * `ghc-9.14.*` / `base-4.22.*`
+ * `ghc-9.12.*` / `base-4.21.*`
+ * `ghc-9.10.*` / `base-4.20.*`
+ * `ghc-9.8.*`  / `base-4.19.*`
+ * `ghc-9.6.*`  / `base-4.18.*`
+ * `ghc-9.4.*`  / `base-4.17.*`
+ * `ghc-9.2.*`  / `base-4.16.*`
  * `ghc-9.0.*`  / `base-4.15.*`
  * `ghc-8.10.*` / `base-4.14.*`
  * `ghc-8.8.*`  / `base-4.13.*`
@@ -313,12 +329,6 @@
  * `ghc-8.4.*`  / `base-4.11.*`
  * `ghc-8.2.*`  / `base-4.10.*`
  * `ghc-8.0.*`  / `base-4.9.*`
- * `ghc-7.10.*` / `base-4.8.*`
- * `ghc-7.8.*`  / `base-4.7.*`
- * `ghc-7.6.*`  / `base-4.6.*`
- * `ghc-7.4.*`  / `base-4.5.*`
- * `ghc-7.2.*`  / `base-4.4.*`
- * `ghc-7.0.*`  / `base-4.3.*`
 
 We also make an attempt to keep `base-compat` building with GHC HEAD, but due
 to its volatility, it may not work at any given point in time. If it doesn't,
diff --git a/base-compat.cabal b/base-compat.cabal
--- a/base-compat.cabal
+++ b/base-compat.cabal
@@ -1,5 +1,5 @@
 name:             base-compat
-version:          0.11.2
+version:          0.15.0
 license:          MIT
 license-file:     LICENSE
 copyright:        (c) 2012-2018 Simon Hengel,
@@ -43,19 +43,21 @@
                   module with the suffix @.Repl@, which are distinct from
                   anything in @base-compat-batteries@, to allow for easier
                   use in GHCi.
-tested-with:        GHC == 7.0.4
-                  , GHC == 7.2.2
-                  , GHC == 7.4.2
-                  , GHC == 7.6.3
-                  , GHC == 7.8.4
-                  , GHC == 7.10.3
-                  , GHC == 8.0.2
+extra-source-files: CHANGES.markdown, README.markdown
+tested-with:        GHC == 8.0.2
                   , GHC == 8.2.2
                   , GHC == 8.4.4
                   , GHC == 8.6.5
-                  , GHC == 8.8.3
-                  , GHC == 8.10.1
-extra-source-files: CHANGES.markdown, README.markdown
+                  , GHC == 8.8.4
+                  , GHC == 8.10.7
+                  , GHC == 9.0.2
+                  , GHC == 9.2.8
+                  , GHC == 9.4.8
+                  , GHC == 9.6.7
+                  , GHC == 9.8.4
+                  , GHC == 9.10.3
+                  , GHC == 9.12.2
+                  , GHC == 9.14.1
 
 source-repository head
   type: git
@@ -68,13 +70,10 @@
   default-language:
       Haskell2010
   build-depends:
-      base >= 4.3 && < 5
-  if !os(windows) && !os(halvm)
-      build-depends: unix
+      base >= 4.9 && < 5,
+      ghc-prim
   ghc-options:
-      -fno-warn-duplicate-exports
-  if impl(ghc >= 7.10)
-    ghc-options: -fno-warn-trustworthy-safe
+      -Wno-duplicate-exports -Wno-trustworthy-safe
 
   hs-source-dirs:
       src
@@ -89,6 +88,7 @@
       Control.Monad.ST.Lazy.Unsafe.Compat
       Control.Monad.ST.Unsafe.Compat
       Data.Bifoldable.Compat
+      Data.Bifoldable1.Compat
       Data.Bifunctor.Compat
       Data.Bitraversable.Compat
       Data.Bits.Compat
@@ -96,6 +96,7 @@
       Data.Complex.Compat
       Data.Either.Compat
       Data.Foldable.Compat
+      Data.Foldable1.Compat
       Data.Function.Compat
       Data.Functor.Compat
       Data.Functor.Compose.Compat
@@ -113,6 +114,9 @@
       Data.Semigroup.Compat
       Data.STRef.Compat
       Data.String.Compat
+      Data.Traversable.Compat
+      Data.Tuple.Compat
+      Data.Typeable.Compat
       Data.Type.Coercion.Compat
       Data.Type.Equality.Compat
       Data.Version.Compat
@@ -138,6 +142,7 @@
       System.IO.Error.Compat
       System.IO.Unsafe.Compat
       Text.Read.Compat
+      Text.Read.Lex.Compat
       Type.Reflection.Compat
 
       Control.Concurrent.Compat.Repl
@@ -149,6 +154,7 @@
       Control.Monad.ST.Lazy.Unsafe.Compat.Repl
       Control.Monad.ST.Unsafe.Compat.Repl
       Data.Bifoldable.Compat.Repl
+      Data.Bifoldable1.Compat.Repl
       Data.Bifunctor.Compat.Repl
       Data.Bitraversable.Compat.Repl
       Data.Bits.Compat.Repl
@@ -156,6 +162,7 @@
       Data.Complex.Compat.Repl
       Data.Either.Compat.Repl
       Data.Foldable.Compat.Repl
+      Data.Foldable1.Compat.Repl
       Data.Function.Compat.Repl
       Data.Functor.Compat.Repl
       Data.Functor.Compose.Compat.Repl
@@ -173,6 +180,9 @@
       Data.Semigroup.Compat.Repl
       Data.STRef.Compat.Repl
       Data.String.Compat.Repl
+      Data.Traversable.Compat.Repl
+      Data.Tuple.Compat.Repl
+      Data.Typeable.Compat.Repl
       Data.Type.Coercion.Compat.Repl
       Data.Type.Equality.Compat.Repl
       Data.Version.Compat.Repl
@@ -198,4 +208,5 @@
       System.IO.Error.Compat.Repl
       System.IO.Unsafe.Compat.Repl
       Text.Read.Compat.Repl
+      Text.Read.Lex.Compat.Repl
       Type.Reflection.Compat.Repl
diff --git a/src/Control/Concurrent/Compat.hs b/src/Control/Concurrent/Compat.hs
--- a/src/Control/Concurrent/Compat.hs
+++ b/src/Control/Concurrent/Compat.hs
@@ -1,8 +1,6 @@
-{-# LANGUAGE CPP, NoImplicitPrelude #-}
+{-# LANGUAGE NoImplicitPrelude #-}
 {-# LANGUAGE RankNTypes #-}
-#if __GLASGOW_HASKELL__ >= 702
 {-# LANGUAGE Trustworthy #-}
-#endif
 module Control.Concurrent.Compat (
   module Base
 , forkFinally
@@ -10,38 +8,3 @@
 ) where
 
 import Control.Concurrent as Base
-
-#if !(MIN_VERSION_base(4,6,0))
-import Control.Exception
-#endif
-
-#if !(MIN_VERSION_base(4,9,0))
-import GHC.IO (unsafeUnmask)
-import Prelude
-#endif
-
-#if !(MIN_VERSION_base(4,6,0))
--- | fork a thread and call the supplied function when the thread is about
--- to terminate, with an exception or a returned value.  The function is
--- called with asynchronous exceptions masked.
---
--- > forkFinally action and_then =
--- >   mask $ \restore ->
--- >     forkIO $ try (restore action) >>= and_then
---
--- This function is useful for informing the parent when a child
--- terminates, for example.
---
--- /Since: 4.6.0.0/
-forkFinally :: IO a -> (Either SomeException a -> IO ()) -> IO ThreadId
-forkFinally action and_then =
-  mask $ \restore ->
-    forkIO $ try (restore action) >>= and_then
-#endif
-
-#if !(MIN_VERSION_base(4,9,0))
--- | Like 'forkIOWithUnmask', but the child thread is a bound thread,
--- as with 'forkOS'.
-forkOSWithUnmask :: ((forall a . IO a -> IO a) -> IO ()) -> IO ThreadId
-forkOSWithUnmask io = forkOS (io unsafeUnmask)
-#endif
diff --git a/src/Control/Concurrent/Compat/Repl.hs b/src/Control/Concurrent/Compat/Repl.hs
--- a/src/Control/Concurrent/Compat/Repl.hs
+++ b/src/Control/Concurrent/Compat/Repl.hs
@@ -1,5 +1,5 @@
 {-# LANGUAGE PackageImports #-}
-{-# OPTIONS_GHC -fno-warn-dodgy-exports -fno-warn-unused-imports #-}
+{-# OPTIONS_GHC -Wno-dodgy-exports -Wno-unused-imports #-}
 -- | Reexports "Control.Concurrent.Compat"
 -- from a globally unique namespace.
 module Control.Concurrent.Compat.Repl (
diff --git a/src/Control/Concurrent/MVar/Compat.hs b/src/Control/Concurrent/MVar/Compat.hs
--- a/src/Control/Concurrent/MVar/Compat.hs
+++ b/src/Control/Concurrent/MVar/Compat.hs
@@ -1,28 +1,6 @@
-{-# LANGUAGE CPP, NoImplicitPrelude #-}
+{-# LANGUAGE NoImplicitPrelude #-}
 module Control.Concurrent.MVar.Compat (
   module Base
 , withMVarMasked
 ) where
 import Control.Concurrent.MVar as Base
-
-#if !(MIN_VERSION_base(4,7,0))
-import Control.Exception (mask_, onException)
-import Control.Monad (return)
-import Data.Function (($))
-import System.IO (IO)
-
-{-|
-  Like 'withMVar', but the @IO@ action in the second argument is executed
-  with asynchronous exceptions masked.
-
-  @since 4.7.0.0
--}
-{-# INLINE withMVarMasked #-}
-withMVarMasked :: MVar a -> (a -> IO b) -> IO b
-withMVarMasked m io =
-  mask_ $ do
-    a <- takeMVar m
-    b <- io a `onException` putMVar m a
-    putMVar m a
-    return b
-#endif
diff --git a/src/Control/Concurrent/MVar/Compat/Repl.hs b/src/Control/Concurrent/MVar/Compat/Repl.hs
--- a/src/Control/Concurrent/MVar/Compat/Repl.hs
+++ b/src/Control/Concurrent/MVar/Compat/Repl.hs
@@ -1,5 +1,5 @@
 {-# LANGUAGE PackageImports #-}
-{-# OPTIONS_GHC -fno-warn-dodgy-exports -fno-warn-unused-imports #-}
+{-# OPTIONS_GHC -Wno-dodgy-exports -Wno-unused-imports #-}
 -- | Reexports "Control.Concurrent.MVar.Compat"
 -- from a globally unique namespace.
 module Control.Concurrent.MVar.Compat.Repl (
diff --git a/src/Control/Exception/Compat.hs b/src/Control/Exception/Compat.hs
--- a/src/Control/Exception/Compat.hs
+++ b/src/Control/Exception/Compat.hs
@@ -1,11 +1,13 @@
 {-# LANGUAGE CPP, NoImplicitPrelude #-}
-#if __GLASGOW_HASKELL__ >= 702
 {-# LANGUAGE Trustworthy #-}
-#endif
 #if MIN_VERSION_base(4,10,0)
+{-# LANGUAGE DataKinds #-}
 {-# LANGUAGE MagicHash #-}
+{-# LANGUAGE PolyKinds #-}
 {-# LANGUAGE RankNTypes #-}
+# if __GLASGOW_HASKELL__ < 806
 {-# LANGUAGE TypeInType #-}
+# endif
 #endif
 module Control.Exception.Compat (
   module Base
diff --git a/src/Control/Exception/Compat/Repl.hs b/src/Control/Exception/Compat/Repl.hs
--- a/src/Control/Exception/Compat/Repl.hs
+++ b/src/Control/Exception/Compat/Repl.hs
@@ -1,5 +1,5 @@
 {-# LANGUAGE PackageImports #-}
-{-# OPTIONS_GHC -fno-warn-dodgy-exports -fno-warn-unused-imports #-}
+{-# OPTIONS_GHC -Wno-dodgy-exports -Wno-unused-imports #-}
 -- | Reexports "Control.Exception.Compat"
 -- from a globally unique namespace.
 module Control.Exception.Compat.Repl (
diff --git a/src/Control/Monad/Compat.hs b/src/Control/Monad/Compat.hs
--- a/src/Control/Monad/Compat.hs
+++ b/src/Control/Monad/Compat.hs
@@ -1,197 +1,11 @@
-{-# LANGUAGE CPP, NoImplicitPrelude #-}
+{-# LANGUAGE NoImplicitPrelude #-}
 module Control.Monad.Compat (
   module Base
 , Monad
-#if MIN_VERSION_base(4,9,0)
 , MonadFail
-#endif
 , fail
 , MonadPlus(..)
-#if !(MIN_VERSION_base(4,8,0))
-, foldM
-, foldM_
-, forM
-, forM_
-, guard
-, mapM
-, mapM_
-, msum
-, sequence
-, sequence_
-, unless
-, when
-
-, (<$!>)
-#endif
-#if !(MIN_VERSION_base(4,9,0))
-, forever
-, filterM
-, mapAndUnzipM
-, zipWithM
-, zipWithM_
-, replicateM
-, replicateM_
-#endif
 ) where
 
-#if MIN_VERSION_base(4,9,0)
 import Control.Monad as Base hiding (fail)
 import Control.Monad.Fail as Base
-#else
-import Control.Monad as Base hiding (
-    forever
-  , filterM
-  , mapAndUnzipM
-  , zipWithM
-  , zipWithM_
-  , replicateM
-  , replicateM_
-# if !(MIN_VERSION_base(4,8,0))
-  , foldM
-  , foldM_
-  , forM
-  , forM_
-  , guard
-  , mapM
-  , mapM_
-  , msum
-  , sequence
-  , sequence_
-  , unless
-  , when
-# endif
-  )
-import Control.Applicative
-import Data.Foldable.Compat
-import Data.Traversable
-import Prelude.Compat
-#endif
-
-#if !(MIN_VERSION_base(4,8,0))
--- | Conditional execution of 'Applicative' expressions. For example,
---
--- > when debug (putStrLn "Debugging")
---
--- will output the string @Debugging@ if the Boolean value @debug@
--- is 'True', and otherwise do nothing.
-when      :: (Applicative f) => Bool -> f () -> f ()
-{-# INLINEABLE when #-}
-{-# SPECIALISE when :: Bool -> IO () -> IO () #-}
-{-# SPECIALISE when :: Bool -> Maybe () -> Maybe () #-}
-when p s  = if p then s else pure ()
-
--- | @'guard' b@ is @'pure' ()@ if @b@ is 'True',
--- and 'empty' if @b@ is 'False'.
-guard           :: (Alternative f) => Bool -> f ()
-guard True      =  pure ()
-guard False     =  empty
-
--- | The reverse of 'when'.
-unless            :: (Applicative f) => Bool -> f () -> f ()
-{-# INLINEABLE unless #-}
-{-# SPECIALISE unless :: Bool -> IO () -> IO () #-}
-{-# SPECIALISE unless :: Bool -> Maybe () -> Maybe () #-}
-unless p s        =  if p then pure () else s
-
-{- | The 'foldM' function is analogous to 'foldl', except that its result is
-encapsulated in a monad. Note that 'foldM' works from left-to-right over
-the list arguments. This could be an issue where @('>>')@ and the `folded
-function' are not commutative.
-
-
->       foldM f a1 [x1, x2, ..., xm]
-
-==
-
->       do
->         a2 <- f a1 x1
->         a3 <- f a2 x2
->         ...
->         f am xm
-
-If right-to-left evaluation is required, the input list should be reversed.
-
-Note: 'foldM' is the same as 'foldlM'
--}
-
-foldM          :: (Foldable t, Monad m) => (b -> a -> m b) -> b -> t a -> m b
-{-# INLINEABLE foldM #-}
-{-# SPECIALISE foldM :: (a -> b -> IO a) -> a -> [b] -> IO a #-}
-{-# SPECIALISE foldM :: (a -> b -> Maybe a) -> a -> [b] -> Maybe a #-}
-foldM          = foldlM
-
--- | Like 'foldM', but discards the result.
-foldM_         :: (Foldable t, Monad m) => (b -> a -> m b) -> b -> t a -> m ()
-{-# INLINEABLE foldM_ #-}
-{-# SPECIALISE foldM_ :: (a -> b -> IO a) -> a -> [b] -> IO () #-}
-{-# SPECIALISE foldM_ :: (a -> b -> Maybe a) -> a -> [b] -> Maybe () #-}
-foldM_ f a xs  = foldlM f a xs >> return ()
-
-infixl 4 <$!>
-
--- | Strict version of 'Data.Functor.<$>'.
---
--- /Since: 4.8.0.0/
-(<$!>) :: Monad m => (a -> b) -> m a -> m b
-{-# INLINE (<$!>) #-}
-f <$!> m = do
-  x <- m
-  let z = f x
-  z `seq` return z
-#endif
-
-#if !(MIN_VERSION_base(4,9,0))
--- | @'forever' act@ repeats the action infinitely.
-forever     :: (Applicative f) => f a -> f b
-{-# INLINE forever #-}
-forever a   = let a' = a *> a' in a'
--- Use explicit sharing here, as it is prevents a space leak regardless of
--- optimizations.
-
--- | This generalizes the list-based 'filter' function.
-{-# INLINE filterM #-}
-filterM          :: (Applicative m) => (a -> m Bool) -> [a] -> m [a]
-filterM p        = foldr (\ x -> liftA2 (\ flg -> if flg then (x:) else id) (p x)) (pure [])
-
--- | The 'mapAndUnzipM' function maps its first argument over a list, returning
--- the result as a pair of lists. This function is mainly used with complicated
--- data structures or a state-transforming monad.
-mapAndUnzipM      :: (Applicative m) => (a -> m (b,c)) -> [a] -> m ([b], [c])
-{-# INLINE mapAndUnzipM #-}
-mapAndUnzipM f xs =  unzip <$> traverse f xs
-
--- | The 'zipWithM' function generalizes 'zipWith' to arbitrary applicative functors.
-zipWithM          :: (Applicative m) => (a -> b -> m c) -> [a] -> [b] -> m [c]
-{-# INLINE zipWithM #-}
-zipWithM f xs ys  =  sequenceA (zipWith f xs ys)
-
--- | 'zipWithM_' is the extension of 'zipWithM' which ignores the final result.
-zipWithM_         :: (Applicative m) => (a -> b -> m c) -> [a] -> [b] -> m ()
-{-# INLINE zipWithM_ #-}
-zipWithM_ f xs ys =  sequenceA_ (zipWith f xs ys)
-
--- | @'replicateM' n act@ performs the action @n@ times,
--- gathering the results.
-replicateM        :: (Applicative m) => Int -> m a -> m [a]
-{-# INLINEABLE replicateM #-}
-{-# SPECIALISE replicateM :: Int -> IO a -> IO [a] #-}
-{-# SPECIALISE replicateM :: Int -> Maybe a -> Maybe [a] #-}
-replicateM cnt0 f =
-    loop cnt0
-  where
-    loop cnt
-        | cnt <= 0  = pure []
-        | otherwise = liftA2 (:) f (loop (cnt - 1))
-
--- | Like 'replicateM', but discards the result.
-replicateM_       :: (Applicative m) => Int -> m a -> m ()
-{-# INLINEABLE replicateM_ #-}
-{-# SPECIALISE replicateM_ :: Int -> IO a -> IO () #-}
-{-# SPECIALISE replicateM_ :: Int -> Maybe a -> Maybe () #-}
-replicateM_ cnt0 f =
-    loop cnt0
-  where
-    loop cnt
-        | cnt <= 0  = pure ()
-        | otherwise = f *> loop (cnt - 1)
-#endif
diff --git a/src/Control/Monad/Compat/Repl.hs b/src/Control/Monad/Compat/Repl.hs
--- a/src/Control/Monad/Compat/Repl.hs
+++ b/src/Control/Monad/Compat/Repl.hs
@@ -1,5 +1,5 @@
 {-# LANGUAGE PackageImports #-}
-{-# OPTIONS_GHC -fno-warn-dodgy-exports -fno-warn-unused-imports #-}
+{-# OPTIONS_GHC -Wno-dodgy-exports -Wno-unused-imports #-}
 -- | Reexports "Control.Monad.Compat"
 -- from a globally unique namespace.
 module Control.Monad.Compat.Repl (
diff --git a/src/Control/Monad/Fail/Compat.hs b/src/Control/Monad/Fail/Compat.hs
--- a/src/Control/Monad/Fail/Compat.hs
+++ b/src/Control/Monad/Fail/Compat.hs
@@ -1,10 +1,6 @@
-{-# LANGUAGE CPP, NoImplicitPrelude #-}
+{-# LANGUAGE NoImplicitPrelude #-}
 module Control.Monad.Fail.Compat (
-#if MIN_VERSION_base(4,9,0)
   module Base
-#endif
 ) where
 
-#if MIN_VERSION_base(4,9,0)
 import Control.Monad.Fail as Base
-#endif
diff --git a/src/Control/Monad/Fail/Compat/Repl.hs b/src/Control/Monad/Fail/Compat/Repl.hs
--- a/src/Control/Monad/Fail/Compat/Repl.hs
+++ b/src/Control/Monad/Fail/Compat/Repl.hs
@@ -1,5 +1,5 @@
 {-# LANGUAGE PackageImports #-}
-{-# OPTIONS_GHC -fno-warn-dodgy-exports -fno-warn-unused-imports #-}
+{-# OPTIONS_GHC -Wno-dodgy-exports -Wno-unused-imports #-}
 -- | Reexports "Control.Monad.Fail.Compat"
 -- from a globally unique namespace.
 module Control.Monad.Fail.Compat.Repl (
diff --git a/src/Control/Monad/IO/Class/Compat.hs b/src/Control/Monad/IO/Class/Compat.hs
--- a/src/Control/Monad/IO/Class/Compat.hs
+++ b/src/Control/Monad/IO/Class/Compat.hs
@@ -1,10 +1,6 @@
-{-# LANGUAGE CPP, NoImplicitPrelude #-}
+{-# LANGUAGE NoImplicitPrelude #-}
 module Control.Monad.IO.Class.Compat (
-#if MIN_VERSION_base(4,9,0)
   module Base
-#endif
 ) where
 
-#if MIN_VERSION_base(4,9,0)
 import Control.Monad.IO.Class as Base
-#endif
diff --git a/src/Control/Monad/IO/Class/Compat/Repl.hs b/src/Control/Monad/IO/Class/Compat/Repl.hs
--- a/src/Control/Monad/IO/Class/Compat/Repl.hs
+++ b/src/Control/Monad/IO/Class/Compat/Repl.hs
@@ -1,5 +1,5 @@
 {-# LANGUAGE PackageImports #-}
-{-# OPTIONS_GHC -fno-warn-dodgy-exports -fno-warn-unused-imports #-}
+{-# OPTIONS_GHC -Wno-dodgy-exports -Wno-unused-imports #-}
 -- | Reexports "Control.Monad.IO.Class.Compat"
 -- from a globally unique namespace.
 module Control.Monad.IO.Class.Compat.Repl (
diff --git a/src/Control/Monad/ST/Lazy/Unsafe/Compat.hs b/src/Control/Monad/ST/Lazy/Unsafe/Compat.hs
--- a/src/Control/Monad/ST/Lazy/Unsafe/Compat.hs
+++ b/src/Control/Monad/ST/Lazy/Unsafe/Compat.hs
@@ -1,12 +1,8 @@
-{-# LANGUAGE CPP, NoImplicitPrelude #-}
+{-# LANGUAGE NoImplicitPrelude #-}
 module Control.Monad.ST.Lazy.Unsafe.Compat (
   -- * Unsafe operations
   unsafeInterleaveST
 , unsafeIOToST
 ) where
 
-#if MIN_VERSION_base(4,6,0)
 import Control.Monad.ST.Lazy.Unsafe (unsafeInterleaveST, unsafeIOToST)
-#else
-import Control.Monad.ST.Lazy (unsafeInterleaveST, unsafeIOToST)
-#endif
diff --git a/src/Control/Monad/ST/Lazy/Unsafe/Compat/Repl.hs b/src/Control/Monad/ST/Lazy/Unsafe/Compat/Repl.hs
--- a/src/Control/Monad/ST/Lazy/Unsafe/Compat/Repl.hs
+++ b/src/Control/Monad/ST/Lazy/Unsafe/Compat/Repl.hs
@@ -1,5 +1,5 @@
 {-# LANGUAGE PackageImports #-}
-{-# OPTIONS_GHC -fno-warn-dodgy-exports -fno-warn-unused-imports #-}
+{-# OPTIONS_GHC -Wno-dodgy-exports -Wno-unused-imports #-}
 -- | Reexports "Control.Monad.ST.Lazy.Unsafe.Compat"
 -- from a globally unique namespace.
 module Control.Monad.ST.Lazy.Unsafe.Compat.Repl (
diff --git a/src/Control/Monad/ST/Unsafe/Compat.hs b/src/Control/Monad/ST/Unsafe/Compat.hs
--- a/src/Control/Monad/ST/Unsafe/Compat.hs
+++ b/src/Control/Monad/ST/Unsafe/Compat.hs
@@ -1,4 +1,4 @@
-{-# LANGUAGE CPP, NoImplicitPrelude #-}
+{-# LANGUAGE NoImplicitPrelude #-}
 module Control.Monad.ST.Unsafe.Compat (
   -- * Unsafe operations
   unsafeInterleaveST
@@ -6,8 +6,4 @@
 , unsafeSTToIO
 ) where
 
-#if MIN_VERSION_base(4,6,0)
 import Control.Monad.ST.Unsafe (unsafeInterleaveST, unsafeIOToST, unsafeSTToIO)
-#else
-import Control.Monad.ST (unsafeInterleaveST, unsafeIOToST, unsafeSTToIO)
-#endif
diff --git a/src/Control/Monad/ST/Unsafe/Compat/Repl.hs b/src/Control/Monad/ST/Unsafe/Compat/Repl.hs
--- a/src/Control/Monad/ST/Unsafe/Compat/Repl.hs
+++ b/src/Control/Monad/ST/Unsafe/Compat/Repl.hs
@@ -1,5 +1,5 @@
 {-# LANGUAGE PackageImports #-}
-{-# OPTIONS_GHC -fno-warn-dodgy-exports -fno-warn-unused-imports #-}
+{-# OPTIONS_GHC -Wno-dodgy-exports -Wno-unused-imports #-}
 -- | Reexports "Control.Monad.ST.Unsafe.Compat"
 -- from a globally unique namespace.
 module Control.Monad.ST.Unsafe.Compat.Repl (
diff --git a/src/Data/Bifoldable/Compat/Repl.hs b/src/Data/Bifoldable/Compat/Repl.hs
--- a/src/Data/Bifoldable/Compat/Repl.hs
+++ b/src/Data/Bifoldable/Compat/Repl.hs
@@ -1,5 +1,5 @@
 {-# LANGUAGE PackageImports #-}
-{-# OPTIONS_GHC -fno-warn-dodgy-exports -fno-warn-unused-imports #-}
+{-# OPTIONS_GHC -Wno-dodgy-exports -Wno-unused-imports #-}
 -- | Reexports "Data.Bifoldable.Compat"
 -- from a globally unique namespace.
 module Data.Bifoldable.Compat.Repl (
diff --git a/src/Data/Bifoldable1/Compat.hs b/src/Data/Bifoldable1/Compat.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/Bifoldable1/Compat.hs
@@ -0,0 +1,10 @@
+{-# LANGUAGE CPP, NoImplicitPrelude #-}
+module Data.Bifoldable1.Compat (
+#if MIN_VERSION_base(4,18,0)
+  module Base
+#endif
+) where
+
+#if MIN_VERSION_base(4,18,0)
+import Data.Bifoldable1 as Base
+#endif
diff --git a/src/Data/Bifoldable1/Compat/Repl.hs b/src/Data/Bifoldable1/Compat/Repl.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/Bifoldable1/Compat/Repl.hs
@@ -0,0 +1,8 @@
+{-# LANGUAGE PackageImports #-}
+{-# OPTIONS_GHC -Wno-dodgy-exports -Wno-unused-imports #-}
+-- | Reexports "Data.Bifoldable1.Compat"
+-- from a globally unique namespace.
+module Data.Bifoldable1.Compat.Repl (
+  module Data.Bifoldable1.Compat
+) where
+import "this" Data.Bifoldable1.Compat
diff --git a/src/Data/Bifunctor/Compat.hs b/src/Data/Bifunctor/Compat.hs
--- a/src/Data/Bifunctor/Compat.hs
+++ b/src/Data/Bifunctor/Compat.hs
@@ -1,10 +1,6 @@
-{-# LANGUAGE CPP, NoImplicitPrelude #-}
+{-# LANGUAGE NoImplicitPrelude #-}
 module Data.Bifunctor.Compat (
-#if MIN_VERSION_base(4,8,0)
   module Base
-#endif
 ) where
 
-#if MIN_VERSION_base(4,8,0)
 import Data.Bifunctor as Base
-#endif
diff --git a/src/Data/Bifunctor/Compat/Repl.hs b/src/Data/Bifunctor/Compat/Repl.hs
--- a/src/Data/Bifunctor/Compat/Repl.hs
+++ b/src/Data/Bifunctor/Compat/Repl.hs
@@ -1,5 +1,5 @@
 {-# LANGUAGE PackageImports #-}
-{-# OPTIONS_GHC -fno-warn-dodgy-exports -fno-warn-unused-imports #-}
+{-# OPTIONS_GHC -Wno-dodgy-exports -Wno-unused-imports #-}
 -- | Reexports "Data.Bifunctor.Compat"
 -- from a globally unique namespace.
 module Data.Bifunctor.Compat.Repl (
diff --git a/src/Data/Bitraversable/Compat.hs b/src/Data/Bitraversable/Compat.hs
--- a/src/Data/Bitraversable/Compat.hs
+++ b/src/Data/Bitraversable/Compat.hs
@@ -2,9 +2,71 @@
 module Data.Bitraversable.Compat (
 #if MIN_VERSION_base(4,10,0)
   module Base
+, firstA
+, secondA
 #endif
 ) where
 
 #if MIN_VERSION_base(4,10,0)
 import Data.Bitraversable as Base
+
+# if !MIN_VERSION_base(4,21,0)
+import Prelude.Compat
+# endif
+
+# if !MIN_VERSION_base(4,21,0)
+-- | Traverses only over the first argument.
+--
+-- @'firstA' f ≡ 'bitraverse' f 'pure'@
+
+-- ==== __Examples__
+--
+-- Basic usage:
+--
+-- >>> firstA listToMaybe (Left [])
+-- Nothing
+--
+-- >>> firstA listToMaybe (Left [1, 2, 3])
+-- Just (Left 1)
+--
+-- >>> firstA listToMaybe (Right [4, 5])
+-- Just (Right [4, 5])
+--
+-- >>> firstA listToMaybe ([1, 2, 3], [4, 5])
+-- Just (1,[4, 5])
+--
+-- >>> firstA listToMaybe ([], [4, 5])
+-- Nothing
+
+-- @since 4.21.0.0
+firstA :: Bitraversable t => Applicative f => (a -> f c) -> t a b -> f (t c b)
+firstA f = bitraverse f pure
+
+-- | Traverses only over the second argument.
+--
+-- @'secondA' f ≡ 'bitraverse' 'pure' f@
+--
+-- ==== __Examples__
+--
+-- Basic usage:
+--
+-- >>> secondA (find odd) (Left [])
+-- Just (Left [])
+--
+-- >>> secondA (find odd) (Left [1, 2, 3])
+-- Just (Left [1,2,3])
+--
+-- >>> secondA (find odd) (Right [4, 5])
+-- Just (Right 5)
+--
+-- >>> secondA (find odd) ([1, 2, 3], [4, 5])
+-- Just ([1,2,3],5)
+--
+-- >>> secondA (find odd) ([1,2,3], [4])
+-- Nothing
+--
+-- @since 4.21.0.0
+secondA :: Bitraversable t => Applicative f => (b -> f c) -> t a b -> f (t a c)
+secondA f = bitraverse pure f
+# endif
 #endif
diff --git a/src/Data/Bitraversable/Compat/Repl.hs b/src/Data/Bitraversable/Compat/Repl.hs
--- a/src/Data/Bitraversable/Compat/Repl.hs
+++ b/src/Data/Bitraversable/Compat/Repl.hs
@@ -1,5 +1,5 @@
 {-# LANGUAGE PackageImports #-}
-{-# OPTIONS_GHC -fno-warn-dodgy-exports -fno-warn-unused-imports #-}
+{-# OPTIONS_GHC -Wno-dodgy-exports -Wno-unused-imports #-}
 -- | Reexports "Data.Bitraversable.Compat"
 -- from a globally unique namespace.
 module Data.Bitraversable.Compat.Repl (
diff --git a/src/Data/Bits/Compat.hs b/src/Data/Bits/Compat.hs
--- a/src/Data/Bits/Compat.hs
+++ b/src/Data/Bits/Compat.hs
@@ -5,122 +5,80 @@
 , bitDefault
 , testBitDefault
 , popCountDefault
-#if MIN_VERSION_base(4,7,0)
+, (.^.)
+, (.>>.)
+, (.<<.)
+, (!>>.)
+, (!<<.)
 , toIntegralSized
-#endif
+, oneBits
 ) where
 
 import Data.Bits as Base
 
-#if !(MIN_VERSION_base(4,8,0))
+#if !(MIN_VERSION_base(4,17,0))
 import Prelude
 #endif
 
-#if !(MIN_VERSION_base(4,6,0))
--- | Default implementation for 'bit'.
---
--- Note that: @bitDefault i = 1 `shiftL` i@
+#if !(MIN_VERSION_base(4,17,0))
+-- | Infix version of 'xor'.
 --
--- /Since: 4.6.0.0/
-bitDefault :: (Bits a, Num a) => Int -> a
-bitDefault = \i -> 1 `shiftL` i
-{-# INLINE bitDefault #-}
+-- /Since: 4.17/
+(.^.) :: (Bits a) => a -> a -> a
+(.^.) = xor
 
--- | Default implementation for 'testBit'.
+infixl 6 .^.
+
+-- | Infix version of 'shiftR'.
 --
--- Note that: @testBitDefault x i = (x .&. bit i) /= 0@
+-- /Since: 4.17/
+(.>>.) :: (Bits a) => a -> Int -> a
+(.>>.) = shiftR
+
+infixl 8 .>>.
+
+-- | Infix version of 'shiftL'.
 --
--- /Since: 4.6.0.0/
-testBitDefault ::  (Bits a, Num a) => a -> Int -> Bool
-testBitDefault = \x i -> (x .&. bit i) /= 0
-{-# INLINE testBitDefault #-}
+-- /Since: 4.17/
+(.<<.) :: (Bits a) => a -> Int -> a
+(.<<.) = shiftL
 
--- | Default implementation for 'popCount'.
+infixl 8 .<<.
+
+-- | Infix version of 'unsafeShiftR'.
 --
--- This implementation is intentionally naive. Instances are expected to provide
--- an optimized implementation for their size.
+-- /Since: 4.17/
+(!>>.) :: (Bits a) => a -> Int -> a
+(!>>.) = unsafeShiftR
+
+infixl 8 !>>.
+
+-- | Infix version of 'unsafeShiftL'.
 --
--- /Since: 4.6.0.0/
-popCountDefault :: (Bits a, Num a) => a -> Int
-popCountDefault = go 0
- where
-   go !c 0 = c
-   go c w = go (c+1) (w .&. (w - 1)) -- clear the least significant
-{-# INLINABLE popCountDefault #-}
+-- /Since: 4.17/
+(!<<.) :: (Bits a) => a -> Int -> a
+(!<<.) = unsafeShiftL
+
+infixl 8 !<<.
 #endif
 
-#if MIN_VERSION_base(4,7,0) && !(MIN_VERSION_base(4,8,0))
--- | Attempt to convert an 'Integral' type @a@ to an 'Integral' type @b@ using
--- the size of the types as measured by 'Bits' methods.
+#if !(MIN_VERSION_base(4,16,0))
+-- | A more concise version of @complement zeroBits@.
 --
--- A simpler version of this function is:
+-- >>> complement (zeroBits :: Word) == (oneBits :: Word)
+-- True
 --
--- > toIntegral :: (Integral a, Integral b) => a -> Maybe b
--- > toIntegral x
--- >   | toInteger x == y = Just (fromInteger y)
--- >   | otherwise        = Nothing
--- >   where
--- >     y = toInteger x
+-- >>> complement (oneBits :: Word) == (zeroBits :: Word)
+-- True
 --
--- This version requires going through 'Integer', which can be inefficient.
--- However, @toIntegralSized@ is optimized to allow GHC to statically determine
--- the relative type sizes (as measured by 'bitSizeMaybe' and 'isSigned') and
--- avoid going through 'Integer' for many types. (The implementation uses
--- 'fromIntegral', which is itself optimized with rules for @base@ types but may
--- go through 'Integer' for some type pairs.)
+-- = Note
 --
--- /Since: 4.8.0.0/
-
-toIntegralSized :: (Integral a, Integral b, Bits a, Bits b) => a -> Maybe b
-toIntegralSized x                 -- See Note [toIntegralSized optimization]
-  | maybe True (<= x) yMinBound
-  , maybe True (x <=) yMaxBound = Just y
-  | otherwise                   = Nothing
-  where
-    y = fromIntegral x
-
-    xWidth = bitSizeMaybe x
-    yWidth = bitSizeMaybe y
-
-    yMinBound
-      | isBitSubType x y = Nothing
-      | isSigned x, not (isSigned y) = Just 0
-      | isSigned x, isSigned y
-      , Just yW <- yWidth = Just (negate $ bit (yW-1)) -- Assumes sub-type
-      | otherwise = Nothing
-
-    yMaxBound
-      | isBitSubType x y = Nothing
-      | isSigned x, not (isSigned y)
-      , Just xW <- xWidth, Just yW <- yWidth
-      , xW <= yW+1 = Nothing -- Max bound beyond a's domain
-      | Just yW <- yWidth = if isSigned y
-                            then Just (bit (yW-1)-1)
-                            else Just (bit yW-1)
-      | otherwise = Nothing
-{-# INLINEABLE toIntegralSized #-}
-
--- | 'True' if the size of @a@ is @<=@ the size of @b@, where size is measured
--- by 'bitSizeMaybe' and 'isSigned'.
-isBitSubType :: (Bits a, Bits b) => a -> b -> Bool
-isBitSubType x y
-  -- Reflexive
-  | xWidth == yWidth, xSigned == ySigned = True
-
-  -- Every integer is a subset of 'Integer'
-  | ySigned, Nothing == yWidth                  = True
-  | not xSigned, not ySigned, Nothing == yWidth = True
-
-  -- Sub-type relations between fixed-with types
-  | xSigned == ySigned,   Just xW <- xWidth, Just yW <- yWidth = xW <= yW
-  | not xSigned, ySigned, Just xW <- xWidth, Just yW <- yWidth = xW <  yW
-
-  | otherwise = False
-  where
-    xWidth  = bitSizeMaybe x
-    xSigned = isSigned     x
-
-    yWidth  = bitSizeMaybe y
-    ySigned = isSigned     y
-{-# INLINE isBitSubType #-}
+-- The constraint on 'oneBits' is arguably too strong. However, as some types
+-- (such as 'Natural') have undefined 'complement', this is the only safe
+-- choice.
+--
+-- /Since: 4.16/
+oneBits :: (FiniteBits a) => a
+oneBits = complement zeroBits
+{-# INLINE oneBits #-}
 #endif
diff --git a/src/Data/Bits/Compat/Repl.hs b/src/Data/Bits/Compat/Repl.hs
--- a/src/Data/Bits/Compat/Repl.hs
+++ b/src/Data/Bits/Compat/Repl.hs
@@ -1,5 +1,5 @@
 {-# LANGUAGE PackageImports #-}
-{-# OPTIONS_GHC -fno-warn-dodgy-exports -fno-warn-unused-imports #-}
+{-# OPTIONS_GHC -Wno-dodgy-exports -Wno-unused-imports #-}
 -- | Reexports "Data.Bits.Compat"
 -- from a globally unique namespace.
 module Data.Bits.Compat.Repl (
diff --git a/src/Data/Bool/Compat.hs b/src/Data/Bool/Compat.hs
--- a/src/Data/Bool/Compat.hs
+++ b/src/Data/Bool/Compat.hs
@@ -1,18 +1,7 @@
-{-# LANGUAGE CPP, NoImplicitPrelude #-}
+{-# LANGUAGE NoImplicitPrelude #-}
 module Data.Bool.Compat (
   module Base
 , bool
 ) where
 
 import Data.Bool as Base
-
-#if !(MIN_VERSION_base(4,7,0))
--- | Case analysis for the 'Bool' type.
--- @bool a b p@ evaluates to @a@ when @p@ is @False@, and evaluates to @b@
--- when @p@ is @True@.
---
--- /Since: 4.7.0.0/
-bool :: a -> a -> Bool -> a
-bool f _ False = f
-bool _ t True  = t
-#endif
diff --git a/src/Data/Bool/Compat/Repl.hs b/src/Data/Bool/Compat/Repl.hs
--- a/src/Data/Bool/Compat/Repl.hs
+++ b/src/Data/Bool/Compat/Repl.hs
@@ -1,5 +1,5 @@
 {-# LANGUAGE PackageImports #-}
-{-# OPTIONS_GHC -fno-warn-dodgy-exports -fno-warn-unused-imports #-}
+{-# OPTIONS_GHC -Wno-dodgy-exports -Wno-unused-imports #-}
 -- | Reexports "Data.Bool.Compat"
 -- from a globally unique namespace.
 module Data.Bool.Compat.Repl (
diff --git a/src/Data/Complex/Compat.hs b/src/Data/Complex/Compat.hs
--- a/src/Data/Complex/Compat.hs
+++ b/src/Data/Complex/Compat.hs
@@ -1,50 +1,6 @@
-{-# LANGUAGE CPP, NoImplicitPrelude #-}
+{-# LANGUAGE NoImplicitPrelude #-}
 module Data.Complex.Compat (
   module Base
-#if MIN_VERSION_base(4,4,0) && !(MIN_VERSION_base(4,8,0))
-, realPart
-, imagPart
-, mkPolar
-, cis
-, conjugate
-#endif
 ) where
 
-#if !(MIN_VERSION_base(4,4,0)) || MIN_VERSION_base(4,8,0)
 import Data.Complex as Base
-#else
-import Data.Complex as Base hiding (
-    realPart
-  , imagPart
-  , mkPolar
-  , cis
-  , conjugate
-  )
-import Prelude
-#endif
-
-#if MIN_VERSION_base(4,4,0) && !(MIN_VERSION_base(4,8,0))
--- | Extracts the real part of a complex number.
-realPart :: Complex a -> a
-realPart (x :+ _) =  x
-
--- | Extracts the imaginary part of a complex number.
-imagPart :: Complex a -> a
-imagPart (_ :+ y) =  y
-
--- | The conjugate of a complex number.
-{-# SPECIALISE conjugate :: Complex Double -> Complex Double #-}
-conjugate        :: Num a => Complex a -> Complex a
-conjugate (x:+y) =  x :+ (-y)
-
--- | Form a complex number from polar components of magnitude and phase.
-{-# SPECIALISE mkPolar :: Double -> Double -> Complex Double #-}
-mkPolar          :: Floating a => a -> a -> Complex a
-mkPolar r theta  =  r * cos theta :+ r * sin theta
-
--- | @'cis' t@ is a complex value with magnitude @1@
--- and phase @t@ (modulo @2*'pi'@).
-{-# SPECIALISE cis :: Double -> Complex Double #-}
-cis              :: Floating a => a -> Complex a
-cis theta        =  cos theta :+ sin theta
-#endif
diff --git a/src/Data/Complex/Compat/Repl.hs b/src/Data/Complex/Compat/Repl.hs
--- a/src/Data/Complex/Compat/Repl.hs
+++ b/src/Data/Complex/Compat/Repl.hs
@@ -1,5 +1,5 @@
 {-# LANGUAGE PackageImports #-}
-{-# OPTIONS_GHC -fno-warn-dodgy-exports -fno-warn-unused-imports #-}
+{-# OPTIONS_GHC -Wno-dodgy-exports -Wno-unused-imports #-}
 -- | Reexports "Data.Complex.Compat"
 -- from a globally unique namespace.
 module Data.Complex.Compat.Repl (
diff --git a/src/Data/Either/Compat.hs b/src/Data/Either/Compat.hs
--- a/src/Data/Either/Compat.hs
+++ b/src/Data/Either/Compat.hs
@@ -8,24 +8,6 @@
 ) where
 import Data.Either as Base
 
-#if !(MIN_VERSION_base(4,7,0))
-import Data.Bool (Bool(..))
-
--- | Return `True` if the given value is a `Left`-value, `False` otherwise.
---
--- /Since: 4.7.0.0/
-isLeft :: Either a b -> Bool
-isLeft (Left  _) = True
-isLeft (Right _) = False
-
--- | Return `True` if the given value is a `Right`-value, `False` otherwise.
---
--- /Since: 4.7.0.0/
-isRight :: Either a b -> Bool
-isRight (Left  _) = False
-isRight (Right _) = True
-#endif
-
 #if !(MIN_VERSION_base(4,10,0))
 -- | Return the contents of a 'Left'-value or a default value otherwise.
 --
diff --git a/src/Data/Either/Compat/Repl.hs b/src/Data/Either/Compat/Repl.hs
--- a/src/Data/Either/Compat/Repl.hs
+++ b/src/Data/Either/Compat/Repl.hs
@@ -1,5 +1,5 @@
 {-# LANGUAGE PackageImports #-}
-{-# OPTIONS_GHC -fno-warn-dodgy-exports -fno-warn-unused-imports #-}
+{-# OPTIONS_GHC -Wno-dodgy-exports -Wno-unused-imports #-}
 -- | Reexports "Data.Either.Compat"
 -- from a globally unique namespace.
 module Data.Either.Compat.Repl (
diff --git a/src/Data/Foldable/Compat.hs b/src/Data/Foldable/Compat.hs
--- a/src/Data/Foldable/Compat.hs
+++ b/src/Data/Foldable/Compat.hs
@@ -1,10 +1,6 @@
 {-# LANGUAGE CPP, NoImplicitPrelude #-}
 module Data.Foldable.Compat (
   module Base
-#if !(MIN_VERSION_base(4,8,0))
-, length
-, null
-#endif
 #if !(MIN_VERSION_base(4,10,0))
 , maximumBy
 , minimumBy
@@ -16,22 +12,6 @@
 #else
 import Data.Foldable as Base hiding (maximumBy, minimumBy)
 import Prelude (Ordering(..))
-#endif
-
-#if !(MIN_VERSION_base(4,8,0))
-import Prelude (Bool(..), Int, (+))
-
--- | Test whether the structure is empty. The default implementation is
--- optimized for structures that are similar to cons-lists, because there
--- is no general way to do better.
-null :: Foldable t => t a -> Bool
-null = foldr (\_ _ -> False) True
-
--- | Returns the size/length of a finite structure as an 'Int'.  The
--- default implementation is optimized for structures that are similar to
--- cons-lists, because there is no general way to do better.
-length :: Foldable t => t a -> Int
-length = foldl' (\c _ -> c+1) 0
 #endif
 
 #if !(MIN_VERSION_base(4,10,0))
diff --git a/src/Data/Foldable/Compat/Repl.hs b/src/Data/Foldable/Compat/Repl.hs
--- a/src/Data/Foldable/Compat/Repl.hs
+++ b/src/Data/Foldable/Compat/Repl.hs
@@ -1,5 +1,5 @@
 {-# LANGUAGE PackageImports #-}
-{-# OPTIONS_GHC -fno-warn-dodgy-exports -fno-warn-unused-imports #-}
+{-# OPTIONS_GHC -Wno-dodgy-exports -Wno-unused-imports #-}
 -- | Reexports "Data.Foldable.Compat"
 -- from a globally unique namespace.
 module Data.Foldable.Compat.Repl (
diff --git a/src/Data/Foldable1/Compat.hs b/src/Data/Foldable1/Compat.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/Foldable1/Compat.hs
@@ -0,0 +1,10 @@
+{-# LANGUAGE CPP, NoImplicitPrelude #-}
+module Data.Foldable1.Compat (
+#if MIN_VERSION_base(4,18,0)
+  module Base
+#endif
+) where
+
+#if MIN_VERSION_base(4,18,0)
+import Data.Foldable1 as Base
+#endif
diff --git a/src/Data/Foldable1/Compat/Repl.hs b/src/Data/Foldable1/Compat/Repl.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/Foldable1/Compat/Repl.hs
@@ -0,0 +1,8 @@
+{-# LANGUAGE PackageImports #-}
+{-# OPTIONS_GHC -Wno-dodgy-exports -Wno-unused-imports #-}
+-- | Reexports "Data.Foldable1.Compat"
+-- from a globally unique namespace.
+module Data.Foldable1.Compat.Repl (
+  module Data.Foldable1.Compat
+) where
+import "this" Data.Foldable1.Compat
diff --git a/src/Data/Function/Compat.hs b/src/Data/Function/Compat.hs
--- a/src/Data/Function/Compat.hs
+++ b/src/Data/Function/Compat.hs
@@ -2,18 +2,39 @@
 module Data.Function.Compat (
   module Base
 , (&)
+, applyWhen
 ) where
 import Data.Function as Base
 
-#if !(MIN_VERSION_base(4,8,0))
-infixl 1 &
+#if !(MIN_VERSION_base(4,18,0))
+import Prelude.Compat
+#endif
 
--- | '&' is a reverse application operator.  This provides notational
--- convenience.  Its precedence is one higher than that of the forward
--- application operator '$', which allows '&' to be nested in '$'.
+#if !(MIN_VERSION_base(4,18,0))
+-- | 'applyWhen' applies a function to a value if a condition is true,
+-- otherwise, it returns the value unchanged.
 --
--- /Since: 4.8.0.0/
-(&) :: a -> (a -> b) -> b
-x & f = f x
-
+-- It is equivalent to @'flip' ('Data.Bool.bool' 'id')@.
+--
+-- Algebraic properties:
+--
+-- * @applyWhen 'True' = 'id'@
+--
+-- * @applyWhen 'False' f = 'id'@
+--
+-- /Since: 4.18.0.0/
+applyWhen :: Bool -> (a -> a) -> a -> a
+applyWhen True  f x = f x
+applyWhen False _ x = x
+-- Proofs:
+--
+-- flip bool id = \q f -> bool id f q
+-- = \f q -> case q of
+--     True -> f = \x -> f x
+--     False -> id = \x -> x ∎
+--
+-- applyWhen True = \f x -> f x
+-- = \f -> \x -> f x = \f -> f = id ∎
+--
+-- applyWhen False f = \x -> x = id ∎
 #endif
diff --git a/src/Data/Function/Compat/Repl.hs b/src/Data/Function/Compat/Repl.hs
--- a/src/Data/Function/Compat/Repl.hs
+++ b/src/Data/Function/Compat/Repl.hs
@@ -1,5 +1,5 @@
 {-# LANGUAGE PackageImports #-}
-{-# OPTIONS_GHC -fno-warn-dodgy-exports -fno-warn-unused-imports #-}
+{-# OPTIONS_GHC -Wno-dodgy-exports -Wno-unused-imports #-}
 -- | Reexports "Data.Function.Compat"
 -- from a globally unique namespace.
 module Data.Function.Compat.Repl (
diff --git a/src/Data/Functor/Compat.hs b/src/Data/Functor/Compat.hs
--- a/src/Data/Functor/Compat.hs
+++ b/src/Data/Functor/Compat.hs
@@ -5,22 +5,12 @@
 , ($>)
 , void
 , (<&>)
+, unzip
 ) where
 import Data.Functor as Base
 
-#if !(MIN_VERSION_base(4,7,0))
-import Control.Monad.Compat (void)
-import Data.Function (flip)
-#endif
-
-#if !(MIN_VERSION_base(4,7,0))
-infixl 4 $>
-
--- | Flipped version of '$>'.
---
--- /Since: 4.7.0.0/
-($>) :: Functor f => f a -> b -> f b
-($>) = flip (<$)
+#if !(MIN_VERSION_base(4,19,0))
+import Data.Tuple (fst, snd)
 #endif
 
 #if !(MIN_VERSION_base(4,11,0))
@@ -48,4 +38,12 @@
 as <&> f = f <$> as
 
 infixl 1 <&>
+#endif
+
+#if !(MIN_VERSION_base(4,19,0))
+-- | Generalization of @Data.List.@'Data.List.unzip'.
+--
+-- /Since: 4.19.0.0/
+unzip :: Functor f => f (a, b) -> (f a, f b)
+unzip xs = (fst <$> xs, snd <$> xs)
 #endif
diff --git a/src/Data/Functor/Compat/Repl.hs b/src/Data/Functor/Compat/Repl.hs
--- a/src/Data/Functor/Compat/Repl.hs
+++ b/src/Data/Functor/Compat/Repl.hs
@@ -1,5 +1,5 @@
 {-# LANGUAGE PackageImports #-}
-{-# OPTIONS_GHC -fno-warn-dodgy-exports -fno-warn-unused-imports #-}
+{-# OPTIONS_GHC -Wno-dodgy-exports -Wno-unused-imports #-}
 -- | Reexports "Data.Functor.Compat"
 -- from a globally unique namespace.
 module Data.Functor.Compat.Repl (
diff --git a/src/Data/Functor/Compose/Compat.hs b/src/Data/Functor/Compose/Compat.hs
--- a/src/Data/Functor/Compose/Compat.hs
+++ b/src/Data/Functor/Compose/Compat.hs
@@ -1,10 +1,6 @@
-{-# LANGUAGE CPP, NoImplicitPrelude #-}
+{-# LANGUAGE NoImplicitPrelude #-}
 module Data.Functor.Compose.Compat (
-#if MIN_VERSION_base(4,9,0)
   module Base
-#endif
 ) where
 
-#if MIN_VERSION_base(4,9,0)
 import Data.Functor.Compose as Base
-#endif
diff --git a/src/Data/Functor/Compose/Compat/Repl.hs b/src/Data/Functor/Compose/Compat/Repl.hs
--- a/src/Data/Functor/Compose/Compat/Repl.hs
+++ b/src/Data/Functor/Compose/Compat/Repl.hs
@@ -1,5 +1,5 @@
 {-# LANGUAGE PackageImports #-}
-{-# OPTIONS_GHC -fno-warn-dodgy-exports -fno-warn-unused-imports #-}
+{-# OPTIONS_GHC -Wno-dodgy-exports -Wno-unused-imports #-}
 -- | Reexports "Data.Functor.Compose.Compat"
 -- from a globally unique namespace.
 module Data.Functor.Compose.Compat.Repl (
diff --git a/src/Data/Functor/Const/Compat/Repl.hs b/src/Data/Functor/Const/Compat/Repl.hs
--- a/src/Data/Functor/Const/Compat/Repl.hs
+++ b/src/Data/Functor/Const/Compat/Repl.hs
@@ -1,5 +1,5 @@
 {-# LANGUAGE PackageImports #-}
-{-# OPTIONS_GHC -fno-warn-dodgy-exports -fno-warn-unused-imports #-}
+{-# OPTIONS_GHC -Wno-dodgy-exports -Wno-unused-imports #-}
 -- | Reexports "Data.Functor.Const.Compat"
 -- from a globally unique namespace.
 module Data.Functor.Const.Compat.Repl (
diff --git a/src/Data/Functor/Contravariant/Compat/Repl.hs b/src/Data/Functor/Contravariant/Compat/Repl.hs
--- a/src/Data/Functor/Contravariant/Compat/Repl.hs
+++ b/src/Data/Functor/Contravariant/Compat/Repl.hs
@@ -1,5 +1,5 @@
 {-# LANGUAGE PackageImports #-}
-{-# OPTIONS_GHC -fno-warn-dodgy-exports -fno-warn-unused-imports #-}
+{-# OPTIONS_GHC -Wno-dodgy-exports -Wno-unused-imports #-}
 -- | Reexports "Data.Functor.Contravariant.Compat"
 -- from a globally unique namespace.
 module Data.Functor.Contravariant.Compat.Repl (
diff --git a/src/Data/Functor/Identity/Compat.hs b/src/Data/Functor/Identity/Compat.hs
--- a/src/Data/Functor/Identity/Compat.hs
+++ b/src/Data/Functor/Identity/Compat.hs
@@ -1,10 +1,6 @@
-{-# LANGUAGE CPP, NoImplicitPrelude #-}
+{-# LANGUAGE NoImplicitPrelude #-}
 module Data.Functor.Identity.Compat (
-#if MIN_VERSION_base(4,8,0)
   module Base
-#endif
 ) where
 
-#if MIN_VERSION_base(4,8,0)
 import Data.Functor.Identity as Base
-#endif
diff --git a/src/Data/Functor/Identity/Compat/Repl.hs b/src/Data/Functor/Identity/Compat/Repl.hs
--- a/src/Data/Functor/Identity/Compat/Repl.hs
+++ b/src/Data/Functor/Identity/Compat/Repl.hs
@@ -1,5 +1,5 @@
 {-# LANGUAGE PackageImports #-}
-{-# OPTIONS_GHC -fno-warn-dodgy-exports -fno-warn-unused-imports #-}
+{-# OPTIONS_GHC -Wno-dodgy-exports -Wno-unused-imports #-}
 -- | Reexports "Data.Functor.Identity.Compat"
 -- from a globally unique namespace.
 module Data.Functor.Identity.Compat.Repl (
diff --git a/src/Data/Functor/Product/Compat.hs b/src/Data/Functor/Product/Compat.hs
--- a/src/Data/Functor/Product/Compat.hs
+++ b/src/Data/Functor/Product/Compat.hs
@@ -1,10 +1,6 @@
-{-# LANGUAGE CPP, NoImplicitPrelude #-}
+{-# LANGUAGE NoImplicitPrelude #-}
 module Data.Functor.Product.Compat (
-#if MIN_VERSION_base(4,9,0)
   module Base
-#endif
 ) where
 
-#if MIN_VERSION_base(4,9,0)
 import Data.Functor.Product as Base
-#endif
diff --git a/src/Data/Functor/Product/Compat/Repl.hs b/src/Data/Functor/Product/Compat/Repl.hs
--- a/src/Data/Functor/Product/Compat/Repl.hs
+++ b/src/Data/Functor/Product/Compat/Repl.hs
@@ -1,5 +1,5 @@
 {-# LANGUAGE PackageImports #-}
-{-# OPTIONS_GHC -fno-warn-dodgy-exports -fno-warn-unused-imports #-}
+{-# OPTIONS_GHC -Wno-dodgy-exports -Wno-unused-imports #-}
 -- | Reexports "Data.Functor.Product.Compat"
 -- from a globally unique namespace.
 module Data.Functor.Product.Compat.Repl (
diff --git a/src/Data/Functor/Sum/Compat.hs b/src/Data/Functor/Sum/Compat.hs
--- a/src/Data/Functor/Sum/Compat.hs
+++ b/src/Data/Functor/Sum/Compat.hs
@@ -1,10 +1,6 @@
-{-# LANGUAGE CPP, NoImplicitPrelude #-}
+{-# LANGUAGE NoImplicitPrelude #-}
 module Data.Functor.Sum.Compat (
-#if MIN_VERSION_base(4,9,0)
   module Base
-#endif
 ) where
 
-#if MIN_VERSION_base(4,9,0)
 import Data.Functor.Sum as Base
-#endif
diff --git a/src/Data/Functor/Sum/Compat/Repl.hs b/src/Data/Functor/Sum/Compat/Repl.hs
--- a/src/Data/Functor/Sum/Compat/Repl.hs
+++ b/src/Data/Functor/Sum/Compat/Repl.hs
@@ -1,5 +1,5 @@
 {-# LANGUAGE PackageImports #-}
-{-# OPTIONS_GHC -fno-warn-dodgy-exports -fno-warn-unused-imports #-}
+{-# OPTIONS_GHC -Wno-dodgy-exports -Wno-unused-imports #-}
 -- | Reexports "Data.Functor.Sum.Compat"
 -- from a globally unique namespace.
 module Data.Functor.Sum.Compat.Repl (
diff --git a/src/Data/IORef/Compat.hs b/src/Data/IORef/Compat.hs
--- a/src/Data/IORef/Compat.hs
+++ b/src/Data/IORef/Compat.hs
@@ -1,4 +1,4 @@
-{-# LANGUAGE CPP, NoImplicitPrelude #-}
+{-# LANGUAGE NoImplicitPrelude #-}
 module Data.IORef.Compat (
   module Base
 , modifyIORef'
@@ -7,36 +7,3 @@
 ) where
 
 import Data.IORef as Base
-
-#if !(MIN_VERSION_base(4,6,0))
-import Prelude
-
--- |Strict version of 'modifyIORef'
---
--- /Since: 4.6.0.0/
-modifyIORef' :: IORef a -> (a -> a) -> IO ()
-modifyIORef' ref f = do
-    x <- readIORef ref
-    let x' = f x
-    x' `seq` writeIORef ref x'
-
--- | Strict version of 'atomicModifyIORef'.  This forces both the value stored
--- in the 'IORef' as well as the value returned.
---
--- /Since: 4.6.0.0/
-atomicModifyIORef' :: IORef a -> (a -> (a,b)) -> IO b
-atomicModifyIORef' ref f = do
-    b <- atomicModifyIORef ref $ \a ->
-            case f a of
-                v@(a',_) -> a' `seq` v
-    b `seq` return b
-
--- | Variant of 'writeIORef' with the \"barrier to reordering\" property that
--- 'atomicModifyIORef' has.
---
--- /Since: 4.6.0.0/
-atomicWriteIORef :: IORef a -> a -> IO ()
-atomicWriteIORef ref a = do
-    x <- atomicModifyIORef ref (\_ -> (a, ()))
-    x `seq` return ()
-#endif
diff --git a/src/Data/IORef/Compat/Repl.hs b/src/Data/IORef/Compat/Repl.hs
--- a/src/Data/IORef/Compat/Repl.hs
+++ b/src/Data/IORef/Compat/Repl.hs
@@ -1,5 +1,5 @@
 {-# LANGUAGE PackageImports #-}
-{-# OPTIONS_GHC -fno-warn-dodgy-exports -fno-warn-unused-imports #-}
+{-# OPTIONS_GHC -Wno-dodgy-exports -Wno-unused-imports #-}
 -- | Reexports "Data.IORef.Compat"
 -- from a globally unique namespace.
 module Data.IORef.Compat.Repl (
diff --git a/src/Data/List/Compat.hs b/src/Data/List/Compat.hs
--- a/src/Data/List/Compat.hs
+++ b/src/Data/List/Compat.hs
@@ -1,219 +1,43 @@
 {-# LANGUAGE CPP, NoImplicitPrelude #-}
 {-# LANGUAGE BangPatterns #-}
-#if __GLASGOW_HASKELL__ >= 702
 {-# LANGUAGE Trustworthy #-}
-#endif
 module Data.List.Compat (
   module Base
-#if !(MIN_VERSION_base(4,15,0))
-, singleton
-#endif
 
-#if !(MIN_VERSION_base(4,11,0))
-, iterate'
+#if !(MIN_VERSION_base(4,21,0))
+, compareLength
+, inits1
+, tails1
 #endif
 
-#if !(MIN_VERSION_base(4,8,0))
-, all
-, and
-, any
-, concat
-, concatMap
-, elem
-, find
-, foldl
-, foldl'
-, foldl1
-, foldr
-, foldr1
-, length
-, maximum
-, maximumBy
-, minimum
-, minimumBy
-, notElem
-, nub
-, nubBy
-, null
-, or
-, product
-, sum
-, union
-, unionBy
-, mapAccumL
-, mapAccumR
-
-, isSubsequenceOf
-, sortOn
-, uncons
-, scanl'
+#if MIN_VERSION_base(4,18,0) && !(MIN_VERSION_base(4,20,0))
+, List
 #endif
 
-#if !(MIN_VERSION_base(4,5,0))
-, dropWhileEnd
+#if !(MIN_VERSION_base(4,19,0))
+, (!?)
+, unsnoc
 #endif
-) where
 
-#if MIN_VERSION_base(4,8,0)
-import Data.List as Base
-#else
-import Data.List as Base hiding (
-    all
-  , and
-  , any
-  , concat
-  , concatMap
-  , elem
-  , find
-  , foldl
-  , foldl'
-  , foldl1
-  , foldr
-  , foldr1
-  , length
-  , maximum
-  , maximumBy
-  , minimum
-  , minimumBy
-  , notElem
-  , nub
-  , nubBy
-  , null
-  , or
-  , product
-  , sum
-  , union
-  , unionBy
-  , mapAccumL
-  , mapAccumR
-  )
-import Data.Foldable.Compat
-import Data.Traversable
-import Data.Ord (comparing)
+#if !(MIN_VERSION_base(4,15,0))
+, singleton
 #endif
 
 #if !(MIN_VERSION_base(4,11,0))
-import GHC.Exts (build)
-import Prelude.Compat hiding (foldr, null)
+, iterate'
 #endif
+) where
 
-#if !(MIN_VERSION_base(4,5,0))
--- | The 'dropWhileEnd' function drops the largest suffix of a list
--- in which the given predicate holds for all elements.  For example:
---
--- > dropWhileEnd isSpace "foo\n" == "foo"
--- > dropWhileEnd isSpace "foo bar" == "foo bar"
--- > dropWhileEnd isSpace ("foo\n" ++ undefined) == "foo" ++ undefined
---
--- /Since: 4.5.0.0/
-dropWhileEnd :: (a -> Bool) -> [a] -> [a]
-dropWhileEnd p = foldr (\x xs -> if p x && null xs then [] else x : xs) []
+import Data.List as Base
 
+#if MIN_VERSION_base(4,18,0) && !(MIN_VERSION_base(4,20,0))
+import GHC.List (List)
 #endif
 
-#if !(MIN_VERSION_base(4,8,0))
--- | The 'isSubsequenceOf' function takes two lists and returns 'True' if the
--- first list is a subsequence of the second list.
---
--- @'isSubsequenceOf' x y@ is equivalent to @'elem' x ('subsequences' y)@.
---
--- /Since: 4.8.0.0/
---
--- ==== __Examples__
---
--- >>> isSubsequenceOf "GHC" "The Glorious Haskell Compiler"
--- True
--- >>> isSubsequenceOf ['a','d'..'z'] ['a'..'z']
--- True
--- >>> isSubsequenceOf [1..10] [10,9..0]
--- False
-isSubsequenceOf :: (Eq a) => [a] -> [a] -> Bool
-isSubsequenceOf []    _                    = True
-isSubsequenceOf _     []                   = False
-isSubsequenceOf a@(x:a') (y:b) | x == y    = isSubsequenceOf a' b
-                               | otherwise = isSubsequenceOf a b
-
--- | Sort a list by comparing the results of a key function applied to each
--- element.  @sortOn f@ is equivalent to @sortBy . comparing f@, but has the
--- performance advantage of only evaluating @f@ once for each element in the
--- input list.  This is called the decorate-sort-undecorate paradigm, or
--- Schwartzian transform.
---
--- /Since: 4.8.0.0/
-sortOn :: Ord b => (a -> b) -> [a] -> [a]
-sortOn f =
-  map snd . sortBy (comparing fst) . map (\x -> let y = f x in y `seq` (y, x))
-
--- | Decompose a list into its head and tail. If the list is empty,
--- returns 'Nothing'. If the list is non-empty, returns @'Just' (x, xs)@,
--- where @x@ is the head of the list and @xs@ its tail.
---
--- /Since: 4.8.0.0/
-uncons                  :: [a] -> Maybe (a, [a])
-uncons []               = Nothing
-uncons (x:xs)           = Just (x, xs)
-
--- | A strictly accumulating version of 'scanl'
-{-# NOINLINE [1] scanl' #-}
-scanl'           :: (b -> a -> b) -> b -> [a] -> [b]
--- This peculiar form is needed to prevent scanl' from being rewritten
--- in its own right hand side.
-scanl' = scanlGo'
-  where
-    scanlGo'           :: (b -> a -> b) -> b -> [a] -> [b]
-    scanlGo' f !q ls    = q : (case ls of
-                            []   -> []
-                            x:xs -> scanlGo' f (f q x) xs)
-
--- | /O(n^2)/. The 'nub' function removes duplicate elements from a list.
--- In particular, it keeps only the first occurrence of each element.
--- (The name 'nub' means \`essence\'.)
--- It is a special case of 'nubBy', which allows the programmer to supply
--- their own equality test.
-nub                     :: (Eq a) => [a] -> [a]
-nub                     =  nubBy (==)
-
-
--- | The 'nubBy' function behaves just like 'nub', except it uses a
--- user-supplied equality predicate instead of the overloaded '=='
--- function.
-nubBy                   :: (a -> a -> Bool) -> [a] -> [a]
--- stolen from HBC
-nubBy eq l              = nubBy' l []
-  where
-    nubBy' [] _         = []
-    nubBy' (y:ys) xs
-       | elem_by eq y xs = nubBy' ys xs
-       | otherwise       = y : nubBy' ys (y:xs)
-
--- Not exported:
--- Note that we keep the call to `eq` with arguments in the
--- same order as in the reference (prelude) implementation,
--- and that this order is different from how `elem` calls (==).
--- See #2528, #3280 and #7913.
--- 'xs' is the list of things we've seen so far,
--- 'y' is the potential new element
-elem_by :: (a -> a -> Bool) -> a -> [a] -> Bool
-elem_by _  _ []         =  False
-elem_by eq y (x:xs)     =  x `eq` y || elem_by eq y xs
-
--- | The 'union' function returns the list union of the two lists.
--- For example,
---
--- > "dog" `union` "cow" == "dogcw"
---
--- Duplicates, and elements of the first list, are removed from the
--- the second list, but if the first list contains duplicates, so will
--- the result.
--- It is a special case of 'unionBy', which allows the programmer to supply
--- their own equality test.
-
-union                   :: (Eq a) => [a] -> [a] -> [a]
-union                   = unionBy (==)
-
--- | The 'unionBy' function is the non-overloaded version of 'union'.
-unionBy                 :: (a -> a -> Bool) -> [a] -> [a] -> [a]
-unionBy eq xs ys        =  xs ++ foldl (flip (deleteBy eq)) (nubBy eq ys) xs
+#if !(MIN_VERSION_base(4,21,0))
+import Data.List.NonEmpty (NonEmpty(..))
+import GHC.Exts (build)
+import Prelude.Compat hiding (foldr, null)
 #endif
 
 #if !(MIN_VERSION_base(4,11,0))
@@ -250,4 +74,164 @@
 --
 singleton :: a -> [a]
 singleton x = [x]
+#endif
+
+#if !(MIN_VERSION_base(4,19,0))
+infixl 9 !?
+-- | List index (subscript) operator, starting from 0. Returns 'Nothing'
+-- if the index is out of bounds
+--
+-- >>> ['a', 'b', 'c'] !? 0
+-- Just 'a'
+-- >>> ['a', 'b', 'c'] !? 2
+-- Just 'c'
+-- >>> ['a', 'b', 'c'] !? 3
+-- Nothing
+-- >>> ['a', 'b', 'c'] !? (-1)
+-- Nothing
+--
+-- This is the total variant of the partial '!!' operator.
+--
+-- WARNING: This function takes linear time in the index.
+(!?) :: [a] -> Int -> Maybe a
+
+{-# INLINABLE (!?) #-}
+xs !? n
+  | n < 0     = Nothing
+  | otherwise = foldr (\x r k -> case k of
+                                   0 -> Just x
+                                   _ -> r (k-1)) (const Nothing) xs n
+
+-- | \(\mathcal{O}(n)\). Decompose a list into 'init' and 'last'.
+--
+-- * If the list is empty, returns 'Nothing'.
+-- * If the list is non-empty, returns @'Just' (xs, x)@,
+-- where @xs@ is the 'init'ial part of the list and @x@ is its 'last' element.
+--
+-- /Since: 4.19.0.0/
+--
+-- >>> unsnoc []
+-- Nothing
+-- >>> unsnoc [1]
+-- Just ([],1)
+-- >>> unsnoc [1, 2, 3]
+-- Just ([1,2],3)
+--
+-- Laziness:
+--
+-- >>> fst <$> unsnoc [undefined]
+-- Just []
+-- >>> head . fst <$> unsnoc (1 : undefined)
+-- Just *** Exception: Prelude.undefined
+-- >>> head . fst <$> unsnoc (1 : 2 : undefined)
+-- Just 1
+--
+-- 'unsnoc' is dual to 'uncons': for a finite list @xs@
+--
+-- > unsnoc xs = (\(hd, tl) -> (reverse tl, hd)) <$> uncons (reverse xs)
+--
+unsnoc :: [a] -> Maybe ([a], a)
+-- The lazy pattern ~(a, b) is important to be productive on infinite lists
+-- and not to be prone to stack overflows.
+-- Expressing the recursion via 'foldr' provides for list fusion.
+unsnoc = foldr (\x -> Just . maybe ([], x) (\(~(a, b)) -> (x : a, b))) Nothing
+{-# INLINABLE unsnoc #-}
+#endif
+
+#if !(MIN_VERSION_base(4,21,0))
+-- | Use 'compareLength' @xs@ @n@ as a safer and faster alternative
+-- to 'compare' ('length' @xs@) @n@. Similarly, it's better
+-- to write @compareLength xs 10 == LT@ instead of @length xs < 10@.
+--
+-- While 'length' would force and traverse
+-- the entire spine of @xs@ (which could even diverge if @xs@ is infinite),
+-- 'compareLength' traverses at most @n@ elements to determine its result.
+--
+-- >>> compareLength [] 0
+-- EQ
+-- >>> compareLength [] 1
+-- LT
+-- >>> compareLength ['a'] 1
+-- EQ
+-- >>> compareLength ['a', 'b'] 1
+-- GT
+-- >>> compareLength [0..] 100
+-- GT
+-- >>> compareLength undefined (-1)
+-- GT
+-- >>> compareLength ('a' : undefined) 0
+-- GT
+--
+-- @since 4.21.0.0
+--
+compareLength :: [a] -> Int -> Ordering
+compareLength xs n
+  | n < 0 = GT
+  | otherwise = foldr
+    (\_ f m -> if m > 0 then f (m - 1) else GT)
+    (\m -> if m > 0 then LT else EQ)
+    xs
+    n
+
+inits1, tails1 :: [a] -> [NonEmpty a]
+
+-- | The 'inits1' function returns all non-empty initial segments of the
+-- argument, shortest first.
+--
+-- @since 4.21.0.0
+--
+-- ==== __Laziness__
+--
+-- Note that 'inits1' has the following strictness property:
+-- @inits1 (xs ++ _|_) = inits1 xs ++ _|_@
+--
+-- In particular,
+-- @inits1 _|_ = _|_@
+--
+-- ==== __Examples__
+--
+-- >>> inits1 "abc"
+-- ['a' :| "",'a' :| "b",'a' :| "bc"]
+--
+-- >>> inits1 []
+-- []
+--
+-- inits1 is productive on infinite lists:
+--
+-- >>> take 3 $ inits1 [1..]
+-- [1 :| [],1 :| [2],1 :| [2,3]]
+inits1 [] = []
+inits1 (x : xs) = map (x :|) (inits xs)
+
+-- | \(\mathcal{O}(n)\). The 'tails1' function returns all non-empty final
+-- segments of the argument, longest first.
+--
+-- @since 4.21.0.0
+--
+-- ==== __Laziness__
+--
+-- Note that 'tails1' has the following strictness property:
+-- @tails1 _|_ = _|_@
+--
+-- >>> tails1 undefined
+-- *** Exception: Prelude.undefined
+--
+-- >>> drop 1 (tails1 [undefined, 1, 2])
+-- [1 :| [2],2 :| []]
+--
+-- ==== __Examples__
+--
+-- >>> tails1 "abc"
+-- ['a' :| "bc",'b' :| "c",'c' :| ""]
+--
+-- >>> tails1 [1, 2, 3]
+-- [1 :| [2,3],2 :| [3],3 :| []]
+--
+-- >>> tails1 []
+-- []
+{-# INLINABLE tails1 #-}
+tails1 lst = build (\c n ->
+  let tails1Go [] = n
+      tails1Go (x : xs) = (x :| xs) `c` tails1Go xs
+  in tails1Go lst)
 #endif
diff --git a/src/Data/List/Compat/Repl.hs b/src/Data/List/Compat/Repl.hs
--- a/src/Data/List/Compat/Repl.hs
+++ b/src/Data/List/Compat/Repl.hs
@@ -1,5 +1,5 @@
 {-# LANGUAGE PackageImports #-}
-{-# OPTIONS_GHC -fno-warn-dodgy-exports -fno-warn-unused-imports #-}
+{-# OPTIONS_GHC -Wno-dodgy-exports -Wno-unused-imports #-}
 -- | Reexports "Data.List.Compat"
 -- from a globally unique namespace.
 module Data.List.Compat.Repl (
diff --git a/src/Data/List/NonEmpty/Compat.hs b/src/Data/List/NonEmpty/Compat.hs
--- a/src/Data/List/NonEmpty/Compat.hs
+++ b/src/Data/List/NonEmpty/Compat.hs
@@ -2,86 +2,289 @@
 -- | This backports the modern "Data.Semigroup" interface back to
 -- @base-4.9@/GHC 8.0.
 module Data.List.NonEmpty.Compat (
-#if MIN_VERSION_base(4,9,0)
   -- * The type of non-empty streams
     NonEmpty(..)
 
   -- * Non-empty stream transformations
-  , map         
-  , intersperse 
-  , scanl       
-  , scanr       
-  , scanl1      
-  , scanr1      
-  , transpose   
-  , sortBy      
-  , sortWith      
+  , map
+  , intersperse
+  , scanl
+  , scanr
+  , scanl1
+  , scanr1
+  , transpose
+  , sortBy
+  , sortWith
   -- * Basic functions
-  , length      
-  , head        
-  , tail        
-  , last        
-  , init        
+  , length
+  , compareLength
+  , head
+  , tail
+  , last
+  , init
   , singleton
-  , (<|), cons  
-  , uncons      
-  , unfoldr     
-  , sort        
-  , reverse     
-  , inits       
-  , tails       
+  , (<|), cons
+  , uncons
+  , unfoldr
+  , sort
+  , sortOn
+  , reverse
+  , inits
+  , inits1
+  , tails
+  , tails1
+  , append
+  , appendList
+  , prependList
   -- * Building streams
-  , iterate     
-  , repeat      
-  , cycle       
-  , unfold      
-  , insert      
-  , some1       
+  , iterate
+  , repeat
+  , cycle
+  , unfold
+  , insert
+  , some1
   -- * Extracting sublists
-  , take        
-  , drop        
-  , splitAt     
-  , takeWhile   
-  , dropWhile   
-  , span        
-  , break       
-  , filter      
-  , partition   
-  , group       
-  , groupBy     
-  , groupWith     
-  , groupAllWith  
-  , group1      
-  , groupBy1    
-  , groupWith1     
-  , groupAllWith1  
+  , take
+  , drop
+  , splitAt
+  , takeWhile
+  , dropWhile
+  , span
+  , break
+  , filter
+  , partition
+  , group
+  , groupBy
+  , groupWith
+  , groupAllWith
+  , group1
+  , groupBy1
+  , groupWith1
+  , groupAllWith1
+  , permutations
+  , permutations1
   -- * Sublist predicates
-  , isPrefixOf  
+  , isPrefixOf
   -- * \"Set\" operations
-  , nub         
-  , nubBy       
+  , nub
+  , nubBy
   -- * Indexing streams
-  , (!!)        
+  , (!!)
   -- * Zipping and unzipping streams
-  , zip         
-  , zipWith     
-  , unzip       
+  , zip
+  , zipWith
+  , unzip
   -- * Converting to and from a list
-  , fromList    
-  , toList      
-  , nonEmpty    
-  , xor         
-#endif
+  , fromList
+  , toList
+  , nonEmpty
+  , xor
 ) where
 
-#if MIN_VERSION_base(4,9,0)
 import Data.List.NonEmpty
+#if !(MIN_VERSION_base(4,22,0))
+  hiding (unzip)
 #endif
 
-#if MIN_VERSION_base(4,9,0) && !(MIN_VERSION_base(4,15,0))
+#if !(MIN_VERSION_base(4,20,0))
+import Prelude.Compat ((.))
+
+import qualified Data.List.Compat as List
+#endif
+
+#if !(MIN_VERSION_base(4,22,0))
+import qualified Prelude.Compat as Prelude
+#endif
+
+#if !(MIN_VERSION_base(4,21,0))
+import Prelude.Compat (Int, Num(..), Ord(..), Ordering(..), otherwise)
+
+import qualified Data.Foldable.Compat as Foldable
+#endif
+
+#if !(MIN_VERSION_base(4,15,0))
 -- | Construct a 'NonEmpty' list from a single element.
 --
 -- /Since: 4.15/
 singleton :: a -> NonEmpty a
 singleton a = a :| []
+#endif
+
+#if !(MIN_VERSION_base(4,16,0))
+-- | A monomorphic version of 'Prelude.<>' for 'NonEmpty'.
+--
+-- >>> append (1 :| []) (2 :| [3])
+-- 1 :| [2,3]
+--
+-- /Since: 4.16/
+append :: NonEmpty a -> NonEmpty a -> NonEmpty a
+append = (Prelude.<>)
+
+-- | Attach a list at the end of a 'NonEmpty'.
+--
+-- >>> appendList (1 :| [2,3]) []
+-- 1 :| [2,3]
+--
+-- >>> appendList (1 :| [2,3]) [4,5]
+-- 1 :| [2,3,4,5]
+--
+-- /Since: 4.16/
+appendList :: NonEmpty a -> [a] -> NonEmpty a
+appendList (x :| xs) ys = x :| xs Prelude.<> ys
+
+-- | Attach a list at the beginning of a 'NonEmpty'.
+--
+-- >>> prependList [] (1 :| [2,3])
+-- 1 :| [2,3]
+--
+-- >>> prependList [negate 1, 0] (1 :| [2, 3])
+-- -1 :| [0,1,2,3]
+--
+-- /Since: 4.16/
+prependList :: [a] -> NonEmpty a -> NonEmpty a
+prependList ls ne = case ls of
+  [] -> ne
+  (x : xs) -> x :| xs Prelude.<> toList ne
+#endif
+
+#if !(MIN_VERSION_base(4,18,0))
+-- | The 'inits1' function takes a 'NonEmpty' stream @xs@ and returns all the
+-- 'NonEmpty' finite prefixes of @xs@, starting with the shortest.
+--
+-- > inits1 (1 :| [2,3]) == (1 :| []) :| [1 :| [2], 1 :| [2,3]]
+-- > inits1 (1 :| []) == (1 :| []) :| []
+--
+-- /Since: 4.18/
+inits1 :: NonEmpty a -> NonEmpty (NonEmpty a)
+inits1 =
+  -- fromList is an unsafe function, but this usage should be safe, since:
+  -- - `inits xs = [[], ..., init (init xs), init xs, xs]`
+  -- - If `xs` is nonempty, it follows that `inits xs` contains at least one nonempty
+  --   list, since `last (inits xs) = xs`.
+  -- - The only empty element of `inits xs` is the first one (by the definition of `inits`)
+  -- - Therefore, if we take all but the first element of `inits xs` i.e.
+  --   `tail (inits xs)`, we have a nonempty list of nonempty lists
+  fromList . Prelude.map fromList . List.tail . List.inits . Foldable.toList
+
+-- | The 'tails1' function takes a 'NonEmpty' stream @xs@ and returns all the
+-- non-empty suffixes of @xs@, starting with the longest.
+--
+-- > tails1 (1 :| [2,3]) == (1 :| [2,3]) :| [2 :| [3], 3 :| []]
+-- > tails1 (1 :| []) == (1 :| []) :| []
+--
+-- /Since: 4.18/
+tails1 :: NonEmpty a -> NonEmpty (NonEmpty a)
+tails1 =
+  -- fromList is an unsafe function, but this usage should be safe, since:
+  -- - `tails xs = [xs, tail xs, tail (tail xs), ..., []]`
+  -- - If `xs` is nonempty, it follows that `tails xs` contains at least one nonempty
+  --   list, since `head (tails xs) = xs`.
+  -- - The only empty element of `tails xs` is the last one (by the definition of `tails`)
+  -- - Therefore, if we take all but the last element of `tails xs` i.e.
+  --   `init (tails xs)`, we have a nonempty list of nonempty lists
+  fromList . Prelude.map fromList . List.init . List.tails . Foldable.toList
+#endif
+
+#if !(MIN_VERSION_base(4,20,0))
+-- | The 'permutations' function returns the list of all permutations of the argument.
+--
+-- /Since: 4.20.0.0/
+permutations            :: [a] -> NonEmpty [a]
+permutations xs0        =  xs0 :| perms xs0 []
+  where
+    perms []     _  = []
+    perms (t:ts) is = List.foldr interleave (perms ts (t:is)) (permutations is)
+      where interleave    xs     r = let (_,zs) = interleave' Prelude.id xs r in zs
+            interleave' _ []     r = (ts, r)
+            interleave' f (y:ys) r = let (us,zs) = interleave' (f . (y:)) ys r
+                                     in  (y:us, f (t:y:us) : zs)
+-- The implementation of 'permutations' is adopted from 'GHC.Internal.Data.List.permutations',
+-- see there for discussion and explanations.
+
+-- | 'permutations1' operates like 'permutations', but uses the knowledge that its input is
+-- non-empty to produce output where every element is non-empty.
+--
+-- > permutations1 = fmap fromList . permutations . toList
+--
+-- /Since: 4.20.0.0/
+permutations1 :: NonEmpty a -> NonEmpty (NonEmpty a)
+permutations1 xs = fromList Prelude.<$> permutations (toList xs)
+
+-- | Sort a 'NonEmpty' on a user-supplied projection of its elements.
+-- See 'List.sortOn' for more detailed information.
+--
+-- ==== __Examples__
+--
+-- >>> sortOn fst $ (2, "world") :| [(4, "!"), (1, "Hello")]
+-- (1,"Hello") :| [(2,"world"),(4,"!")]
+--
+-- >>> sortOn length $ "jim" :| ["creed", "pam", "michael", "dwight", "kevin"]
+-- "jim" :| ["pam","creed","kevin","dwight","michael"]
+--
+-- ==== __Performance notes__
+--
+-- This function minimises the projections performed, by materialising
+-- the projections in an intermediate list.
+--
+-- For trivial projections, you should prefer using 'sortBy' with
+-- 'comparing', for example:
+--
+-- >>> sortBy (comparing fst) $ (3, 1) :| [(2, 2), (1, 3)]
+-- (1,3) :| [(2,2),(3,1)]
+--
+-- Or, for the exact same API as 'sortOn', you can use `sortBy . comparing`:
+--
+-- >>> (sortBy . comparing) fst $ (3, 1) :| [(2, 2), (1, 3)]
+-- (1,3) :| [(2,2),(3,1)]
+--
+-- 'sortWith' is an alias for `sortBy . comparing`.
+--
+-- /Since: 4.20.0.0/
+sortOn :: Prelude.Ord b => (a -> b) -> NonEmpty a -> NonEmpty a
+sortOn f = lift (List.sortOn f)
+
+-- | Lift list operations to work on a 'NonEmpty' stream.
+--
+-- /Beware/: If the provided function returns an empty list,
+-- this will raise an error.
+lift :: Foldable.Foldable f => ([a] -> [b]) -> f a -> NonEmpty b
+lift f = fromList . f . Foldable.toList
+#endif
+
+#if !(MIN_VERSION_base(4,21,0))
+-- | Use 'compareLength' @xs@ @n@ as a safer and faster alternative
+-- to 'compare' ('length' @xs@) @n@. Similarly, it's better
+-- to write @compareLength xs 10 == LT@ instead of @length xs < 10@.
+--
+-- While 'length' would force and traverse
+-- the entire spine of @xs@ (which could even diverge if @xs@ is infinite),
+-- 'compareLength' traverses at most @n@ elements to determine its result.
+--
+-- >>> compareLength ('a' :| []) 1
+-- EQ
+-- >>> compareLength ('a' :| ['b']) 3
+-- LT
+-- >>> compareLength (0 :| [1..]) 100
+-- GT
+-- >>> compareLength undefined 0
+-- GT
+-- >>> compareLength ('a' :| 'b' : undefined) 1
+-- GT
+--
+-- @since 4.21.0.0
+--
+compareLength :: NonEmpty a -> Int -> Ordering
+compareLength xs n
+  | n < 1 = GT
+  | otherwise = Foldable.foldr
+    (\_ f m -> if m > 0 then f (m - 1) else GT)
+    (\m -> if m > 0 then LT else EQ)
+    xs
+    n
+#endif
+
+#if !(MIN_VERSION_base(4,22,0))
+-- | The 'unzip' function is the inverse of the 'zip' function.
+unzip :: NonEmpty (a, b) -> (NonEmpty a, NonEmpty b)
+unzip xs = (Prelude.fst Prelude.<$> xs, Prelude.snd Prelude.<$> xs)
 #endif
diff --git a/src/Data/List/NonEmpty/Compat/Repl.hs b/src/Data/List/NonEmpty/Compat/Repl.hs
--- a/src/Data/List/NonEmpty/Compat/Repl.hs
+++ b/src/Data/List/NonEmpty/Compat/Repl.hs
@@ -1,5 +1,5 @@
 {-# LANGUAGE PackageImports #-}
-{-# OPTIONS_GHC -fno-warn-dodgy-exports -fno-warn-unused-imports #-}
+{-# OPTIONS_GHC -Wno-dodgy-exports -Wno-unused-imports #-}
 -- | Reexports "Data.List.NonEmpty.Compat"
 -- from a globally unique namespace.
 module Data.List.NonEmpty.Compat.Repl (
diff --git a/src/Data/Monoid/Compat.hs b/src/Data/Monoid/Compat.hs
--- a/src/Data/Monoid/Compat.hs
+++ b/src/Data/Monoid/Compat.hs
@@ -1,26 +1,8 @@
-{-# LANGUAGE CPP, NoImplicitPrelude #-}
+{-# LANGUAGE NoImplicitPrelude #-}
 module Data.Monoid.Compat (
   module Base
 , (<>)
 ) where
 
-import Data.Monoid as Base
-#if MIN_VERSION_base(4,9,0)
-  hiding ((<>))
-#endif
-#if MIN_VERSION_base(4,9,0)
+import Data.Monoid as Base hiding ((<>))
 import Data.Semigroup ((<>))
-#endif
-
-#if !(MIN_VERSION_base(4,5,0)) && !(MIN_VERSION_base(4,9,0))
-
-infixr 6 <>
-
--- | An infix synonym for 'mappend'.
---
--- /Since: 4.5.0.0/
-(<>) :: Monoid m => m -> m -> m
-(<>) = mappend
-{-# INLINE (<>) #-}
-
-#endif
diff --git a/src/Data/Monoid/Compat/Repl.hs b/src/Data/Monoid/Compat/Repl.hs
--- a/src/Data/Monoid/Compat/Repl.hs
+++ b/src/Data/Monoid/Compat/Repl.hs
@@ -1,5 +1,5 @@
 {-# LANGUAGE PackageImports #-}
-{-# OPTIONS_GHC -fno-warn-dodgy-exports -fno-warn-unused-imports #-}
+{-# OPTIONS_GHC -Wno-dodgy-exports -Wno-unused-imports #-}
 -- | Reexports "Data.Monoid.Compat"
 -- from a globally unique namespace.
 module Data.Monoid.Compat.Repl (
diff --git a/src/Data/Proxy/Compat.hs b/src/Data/Proxy/Compat.hs
--- a/src/Data/Proxy/Compat.hs
+++ b/src/Data/Proxy/Compat.hs
@@ -1,17 +1,13 @@
 {-# LANGUAGE CPP, NoImplicitPrelude #-}
 module Data.Proxy.Compat (
-#if MIN_VERSION_base(4,7,0)
   module Base,
-#endif
   asProxyTypeOf
 ) where
 
-#if MIN_VERSION_base(4,7,0)
-# if MIN_VERSION_base(4,10,0)
+#if MIN_VERSION_base(4,10,0)
 import Data.Proxy as Base
-# else
+#else
 import Data.Proxy as Base hiding (asProxyTypeOf)
-# endif
 #endif
 
 #if !(MIN_VERSION_base(4,10,0))
diff --git a/src/Data/Proxy/Compat/Repl.hs b/src/Data/Proxy/Compat/Repl.hs
--- a/src/Data/Proxy/Compat/Repl.hs
+++ b/src/Data/Proxy/Compat/Repl.hs
@@ -1,5 +1,5 @@
 {-# LANGUAGE PackageImports #-}
-{-# OPTIONS_GHC -fno-warn-dodgy-exports -fno-warn-unused-imports #-}
+{-# OPTIONS_GHC -Wno-dodgy-exports -Wno-unused-imports #-}
 -- | Reexports "Data.Proxy.Compat"
 -- from a globally unique namespace.
 module Data.Proxy.Compat.Repl (
diff --git a/src/Data/Ratio/Compat.hs b/src/Data/Ratio/Compat.hs
--- a/src/Data/Ratio/Compat.hs
+++ b/src/Data/Ratio/Compat.hs
@@ -1,32 +1,6 @@
-{-# LANGUAGE CPP, NoImplicitPrelude #-}
+{-# LANGUAGE NoImplicitPrelude #-}
 module Data.Ratio.Compat (
   module Base
-#if MIN_VERSION_base(4,4,0) && !(MIN_VERSION_base(4,9,0))
-, denominator
-, numerator
-#endif
 ) where
 
-#if !(MIN_VERSION_base(4,4,0)) || MIN_VERSION_base(4,9,0)
 import Data.Ratio as Base
-#else
-import Data.Ratio as Base hiding (
-    denominator
-  , numerator
-  )
-import GHC.Real (Ratio(..))
-#endif
-
-#if MIN_VERSION_base(4,4,0) && !(MIN_VERSION_base(4,9,0))
--- | Extract the numerator of the ratio in reduced form:
--- the numerator and denominator have no common factor and the denominator
--- is positive.
-numerator :: Ratio a -> a
-numerator (x :% _) = x
-
--- | Extract the denominator of the ratio in reduced form:
--- the numerator and denominator have no common factor and the denominator
--- is positive.
-denominator :: Ratio a -> a
-denominator (_ :% y) =  y
-#endif
diff --git a/src/Data/Ratio/Compat/Repl.hs b/src/Data/Ratio/Compat/Repl.hs
--- a/src/Data/Ratio/Compat/Repl.hs
+++ b/src/Data/Ratio/Compat/Repl.hs
@@ -1,5 +1,5 @@
 {-# LANGUAGE PackageImports #-}
-{-# OPTIONS_GHC -fno-warn-dodgy-exports -fno-warn-unused-imports #-}
+{-# OPTIONS_GHC -Wno-dodgy-exports -Wno-unused-imports #-}
 -- | Reexports "Data.Ratio.Compat"
 -- from a globally unique namespace.
 module Data.Ratio.Compat.Repl (
diff --git a/src/Data/STRef/Compat.hs b/src/Data/STRef/Compat.hs
--- a/src/Data/STRef/Compat.hs
+++ b/src/Data/STRef/Compat.hs
@@ -1,24 +1,8 @@
-{-# LANGUAGE CPP, NoImplicitPrelude #-}
-#if __GLASGOW_HASKELL__ >= 702
+{-# LANGUAGE NoImplicitPrelude #-}
 {-# LANGUAGE Trustworthy #-}
-#endif
 module Data.STRef.Compat (
   module Base
 , modifySTRef'
 ) where
 
 import Data.STRef as Base
-
-#if !(MIN_VERSION_base(4,6,0))
-import Control.Monad.ST (ST)
-import Prelude (seq)
-
--- | Strict version of 'modifySTRef'
---
--- /Since: 4.6.0.0/
-modifySTRef' :: STRef s a -> (a -> a) -> ST s ()
-modifySTRef' ref f = do
-    x <- readSTRef ref
-    let x' = f x
-    x' `seq` writeSTRef ref x'
-#endif
diff --git a/src/Data/STRef/Compat/Repl.hs b/src/Data/STRef/Compat/Repl.hs
--- a/src/Data/STRef/Compat/Repl.hs
+++ b/src/Data/STRef/Compat/Repl.hs
@@ -1,5 +1,5 @@
 {-# LANGUAGE PackageImports #-}
-{-# OPTIONS_GHC -fno-warn-dodgy-exports -fno-warn-unused-imports #-}
+{-# OPTIONS_GHC -Wno-dodgy-exports -Wno-unused-imports #-}
 -- | Reexports "Data.STRef.Compat"
 -- from a globally unique namespace.
 module Data.STRef.Compat.Repl (
diff --git a/src/Data/Semigroup/Compat.hs b/src/Data/Semigroup/Compat.hs
--- a/src/Data/Semigroup/Compat.hs
+++ b/src/Data/Semigroup/Compat.hs
@@ -1,8 +1,7 @@
-{-# LANGUAGE CPP, NoImplicitPrelude #-}
+{-# LANGUAGE NoImplicitPrelude #-}
 -- | This backports the modern "Data.Semigroup" interface back to
 -- @base-4.9@/GHC 8.0.
 module Data.Semigroup.Compat (
-#if MIN_VERSION_base(4,9,0)
     Semigroup(..)
   , stimesMonoid
   , stimesIdempotent
@@ -21,9 +20,6 @@
   , Any(..)
   , Sum(..)
   , Product(..)
-  -- * A better monoid for Maybe
-  , Option(..)
-  , option
   -- * Difference lists of a semigroup
   , diff
   , cycle1
@@ -31,9 +27,6 @@
   , Arg(..)
   , ArgMin
   , ArgMax
-#endif
   ) where
 
-#if MIN_VERSION_base(4,9,0)
 import Data.Semigroup
-#endif
diff --git a/src/Data/Semigroup/Compat/Repl.hs b/src/Data/Semigroup/Compat/Repl.hs
--- a/src/Data/Semigroup/Compat/Repl.hs
+++ b/src/Data/Semigroup/Compat/Repl.hs
@@ -1,5 +1,5 @@
 {-# LANGUAGE PackageImports #-}
-{-# OPTIONS_GHC -fno-warn-dodgy-exports -fno-warn-unused-imports #-}
+{-# OPTIONS_GHC -Wno-dodgy-exports -Wno-unused-imports #-}
 -- | Reexports "Data.Semigroup.Compat"
 -- from a globally unique namespace.
 module Data.Semigroup.Compat.Repl (
diff --git a/src/Data/String/Compat.hs b/src/Data/String/Compat.hs
--- a/src/Data/String/Compat.hs
+++ b/src/Data/String/Compat.hs
@@ -1,4 +1,4 @@
-{-# LANGUAGE CPP, NoImplicitPrelude #-}
+{-# LANGUAGE NoImplicitPrelude #-}
 module Data.String.Compat (
   module Base
 , String
@@ -9,7 +9,3 @@
 ) where
 
 import Data.String as Base
-
-#if !(MIN_VERSION_base(4,4,0))
-import Prelude (String, lines, words, unlines, unwords)
-#endif
diff --git a/src/Data/String/Compat/Repl.hs b/src/Data/String/Compat/Repl.hs
--- a/src/Data/String/Compat/Repl.hs
+++ b/src/Data/String/Compat/Repl.hs
@@ -1,5 +1,5 @@
 {-# LANGUAGE PackageImports #-}
-{-# OPTIONS_GHC -fno-warn-dodgy-exports -fno-warn-unused-imports #-}
+{-# OPTIONS_GHC -Wno-dodgy-exports -Wno-unused-imports #-}
 -- | Reexports "Data.String.Compat"
 -- from a globally unique namespace.
 module Data.String.Compat.Repl (
diff --git a/src/Data/Traversable/Compat.hs b/src/Data/Traversable/Compat.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/Traversable/Compat.hs
@@ -0,0 +1,98 @@
+{-# LANGUAGE CPP, NoImplicitPrelude #-}
+{-# LANGUAGE Trustworthy #-}
+#if !(MIN_VERSION_base(4,18,0))
+{-# LANGUAGE ScopedTypeVariables #-}
+#endif
+module Data.Traversable.Compat (
+  module Base
+, mapAccumM
+, forAccumM
+) where
+
+import Data.Traversable as Base
+
+#if !(MIN_VERSION_base(4,18,0))
+import Prelude.Compat
+
+import Control.Monad.Compat (liftM)
+
+import Data.Coerce (Coercible, coerce)
+#endif
+
+#if !(MIN_VERSION_base(4,18,0))
+-- | A state transformer monad parameterized by the state and inner monad.
+-- The implementation is copied from the transformers package with the
+-- return tuple swapped.
+--
+-- /Since: 4.18.0.0/
+newtype StateT s m a = StateT { runStateT :: s -> m (s, a) }
+
+-- | /Since: 4.18.0.0/
+instance Monad m => Functor (StateT s m) where
+    fmap = liftM
+    {-# INLINE fmap #-}
+
+-- | /Since: 4.18.0.0/
+instance Monad m => Applicative (StateT s m) where
+    pure a = StateT $ \ s -> return (s, a)
+    {-# INLINE pure #-}
+    StateT mf <*> StateT mx = StateT $ \ s -> do
+        (s', f) <- mf s
+        (s'', x) <- mx s'
+        return (s'', f x)
+    {-# INLINE (<*>) #-}
+    m *> k = m >>= \_ -> k
+    {-# INLINE (*>) #-}
+
+(#.) :: Coercible b c => (b -> c) -> (a -> b) -> (a -> c)
+(#.) _f = coerce
+
+-- | /Since: 4.18.0.0/
+instance (Monad m) => Monad (StateT s m) where
+    m >>= k  = StateT $ \ s -> do
+        (s', a) <- runStateT m s
+        runStateT (k a) s'
+    {-# INLINE (>>=) #-}
+# if !(MIN_VERSION_base(4,11,0))
+    return = pure
+# endif
+
+-- | The `mapAccumM` function behaves like a combination of `mapM` and
+-- `mapAccumL` that traverses the structure while evaluating the actions
+-- and passing an accumulating parameter from left to right.
+-- It returns a final value of this accumulator together with the new structure.
+-- The accummulator is often used for caching the intermediate results of a computation.
+--
+--  @since 4.18.0.0
+--
+-- ==== __Examples__
+--
+-- Basic usage:
+--
+-- >>> let expensiveDouble a = putStrLn ("Doubling " <> show a) >> pure (2 * a)
+-- >>> :{
+-- mapAccumM (\cache a -> case lookup a cache of
+--     Nothing -> expensiveDouble a >>= \double -> pure ((a, double):cache, double)
+--     Just double -> pure (cache, double)
+--     ) [] [1, 2, 3, 1, 2, 3]
+-- :}
+-- Doubling 1
+-- Doubling 2
+-- Doubling 3
+-- ([(3,6),(2,4),(1,2)],[2,4,6,2,4,6])
+--
+mapAccumM
+  :: forall m t s a b. (Monad m, Traversable t)
+  => (s -> a -> m (s, b))
+  -> s -> t a -> m (s, t b)
+mapAccumM f s t = runStateT (mapM (StateT #. flip f) t) s
+
+-- | 'forAccumM' is 'mapAccumM' with the arguments rearranged.
+--
+-- @since 4.18.0.0
+forAccumM
+  :: (Monad m, Traversable t)
+  => s -> t a -> (s -> a -> m (s, b)) -> m (s, t b)
+{-# INLINE forAccumM #-}
+forAccumM s t f = mapAccumM f s t
+#endif
diff --git a/src/Data/Traversable/Compat/Repl.hs b/src/Data/Traversable/Compat/Repl.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/Traversable/Compat/Repl.hs
@@ -0,0 +1,8 @@
+{-# LANGUAGE PackageImports #-}
+{-# OPTIONS_GHC -Wno-dodgy-exports -Wno-unused-imports #-}
+-- | Reexports "Data.Traversable.Compat"
+-- from a globally unique namespace.
+module Data.Traversable.Compat.Repl (
+  module Data.Traversable.Compat
+) where
+import "this" Data.Traversable.Compat
diff --git a/src/Data/Tuple/Compat.hs b/src/Data/Tuple/Compat.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/Tuple/Compat.hs
@@ -0,0 +1,34 @@
+{-# LANGUAGE CPP, NoImplicitPrelude #-}
+{-# LANGUAGE Safe #-}
+#if MIN_VERSION_ghc_prim(0,7,0)
+{-# LANGUAGE PatternSynonyms #-}
+#endif
+-- | Note that we only re-export @MkSolo@ when building with @ghc-prim-0.10.0@
+-- (bundled with GHC 9.6) or later. If you want to backport @MkSolo@ to older
+-- versions of GHC, import @Data.Tuple.Compat@ from @base-compat-batteries@
+-- instead.
+module Data.Tuple.Compat
+  ( fst
+  , snd
+  , curry
+  , uncurry
+  , swap
+#if MIN_VERSION_ghc_prim(0,10,0)
+  , Solo(MkSolo,Solo)
+#elif MIN_VERSION_ghc_prim(0,7,0)
+  , Solo(Solo)
+#endif
+#if MIN_VERSION_ghc_prim(0,8,0)
+  , getSolo
+#endif
+  ) where
+
+import Data.Tuple
+
+#if !(MIN_VERSION_base(4,16,0)) && MIN_VERSION_ghc_prim(0,7,0)
+import GHC.Tuple (Solo(..))
+#endif
+
+#if MIN_VERSION_ghc_prim(0,8,0) && !(MIN_VERSION_ghc_prim(0,11,0))
+import GHC.Tuple (getSolo)
+#endif
diff --git a/src/Data/Tuple/Compat/Repl.hs b/src/Data/Tuple/Compat/Repl.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/Tuple/Compat/Repl.hs
@@ -0,0 +1,8 @@
+{-# LANGUAGE PackageImports #-}
+{-# OPTIONS_GHC -Wno-dodgy-exports -Wno-unused-imports #-}
+-- | Reexports "Data.Tuple.Compat"
+-- from a globally unique namespace.
+module Data.Tuple.Compat.Repl (
+  module Data.Tuple.Compat
+) where
+import "this" Data.Tuple.Compat
diff --git a/src/Data/Type/Coercion/Compat.hs b/src/Data/Type/Coercion/Compat.hs
--- a/src/Data/Type/Coercion/Compat.hs
+++ b/src/Data/Type/Coercion/Compat.hs
@@ -1,16 +1,11 @@
 {-# LANGUAGE CPP, NoImplicitPrelude #-}
 {-# LANGUAGE RankNTypes #-}
-#if __GLASGOW_HASKELL__ >= 702
 {-# LANGUAGE Trustworthy #-}
-#endif
 module Data.Type.Coercion.Compat (
-#if MIN_VERSION_base(4,7,0)
   module Base
 , gcoerceWith
-#endif
 ) where
 
-#if MIN_VERSION_base(4,7,0)
 import Data.Type.Coercion as Base
 
 # if !(MIN_VERSION_base(4,10,0))
@@ -22,4 +17,3 @@
 gcoerceWith :: Coercion a b -> (Coercible a b => r) -> r
 gcoerceWith Coercion x = x
 # endif
-#endif
diff --git a/src/Data/Type/Coercion/Compat/Repl.hs b/src/Data/Type/Coercion/Compat/Repl.hs
--- a/src/Data/Type/Coercion/Compat/Repl.hs
+++ b/src/Data/Type/Coercion/Compat/Repl.hs
@@ -1,5 +1,5 @@
 {-# LANGUAGE PackageImports #-}
-{-# OPTIONS_GHC -fno-warn-dodgy-exports -fno-warn-unused-imports #-}
+{-# OPTIONS_GHC -Wno-dodgy-exports -Wno-unused-imports #-}
 -- | Reexports "Data.Type.Coercion.Compat"
 -- from a globally unique namespace.
 module Data.Type.Coercion.Compat.Repl (
diff --git a/src/Data/Type/Equality/Compat.hs b/src/Data/Type/Equality/Compat.hs
--- a/src/Data/Type/Equality/Compat.hs
+++ b/src/Data/Type/Equality/Compat.hs
@@ -1,14 +1,8 @@
-{-# LANGUAGE CPP, NoImplicitPrelude #-}
+{-# LANGUAGE NoImplicitPrelude #-}
 {-# LANGUAGE RankNTypes #-}
-#if __GLASGOW_HASKELL__ >= 702
 {-# LANGUAGE Trustworthy #-}
-#endif
 module Data.Type.Equality.Compat (
-#if MIN_VERSION_base(4,7,0)
   module Base
-#endif
 ) where
 
-#if MIN_VERSION_base(4,7,0)
 import Data.Type.Equality as Base
-#endif
diff --git a/src/Data/Type/Equality/Compat/Repl.hs b/src/Data/Type/Equality/Compat/Repl.hs
--- a/src/Data/Type/Equality/Compat/Repl.hs
+++ b/src/Data/Type/Equality/Compat/Repl.hs
@@ -1,5 +1,5 @@
 {-# LANGUAGE PackageImports #-}
-{-# OPTIONS_GHC -fno-warn-dodgy-exports -fno-warn-unused-imports #-}
+{-# OPTIONS_GHC -Wno-dodgy-exports -Wno-unused-imports #-}
 -- | Reexports "Data.Type.Equality.Compat"
 -- from a globally unique namespace.
 module Data.Type.Equality.Compat.Repl (
diff --git a/src/Data/Typeable/Compat.hs b/src/Data/Typeable/Compat.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/Typeable/Compat.hs
@@ -0,0 +1,58 @@
+{-# LANGUAGE CPP, NoImplicitPrelude #-}
+{-# LANGUAGE Trustworthy #-}
+#if MIN_VERSION_base(4,10,0) && !(MIN_VERSION_base(4,19,0))
+{-# LANGUAGE GADTs #-}
+{-# LANGUAGE PolyKinds #-}
+{-# LANGUAGE ScopedTypeVariables #-}
+{-# LANGUAGE TypeApplications #-}
+{-# LANGUAGE TypeOperators #-}
+#endif
+module Data.Typeable.Compat (
+  module Base
+#if MIN_VERSION_base(4,10,0)
+, heqT
+, decT
+, hdecT
+#endif
+) where
+
+import Data.Typeable as Base
+
+#if MIN_VERSION_base(4,10,0) && !(MIN_VERSION_base(4,19,0))
+import Prelude.Compat
+
+import Data.Void (Void)
+import qualified Type.Reflection.Compat as TR
+#endif
+
+#if MIN_VERSION_base(4,10,0)
+# if !(MIN_VERSION_base(4,18,0))
+-- | Extract a witness of heterogeneous equality of two types
+--
+-- /Since: 4.18.0.0/
+heqT :: forall a b. (Typeable a, Typeable b) => Maybe (a :~~: b)
+heqT = ta `TR.eqTypeRep` tb
+  where
+    ta = TR.typeRep :: TR.TypeRep a
+    tb = TR.typeRep :: TR.TypeRep b
+# endif
+
+# if !(MIN_VERSION_base(4,19,0))
+-- | Decide an equality of two types
+--
+-- /Since: 4.19.0.0/
+decT :: forall a b. (Typeable a, Typeable b) => Either (a :~: b -> Void) (a :~: b)
+decT = case hdecT @a @b of
+  Right HRefl -> Right Refl
+  Left p      -> Left (\Refl -> p HRefl)
+
+-- | Decide heterogeneous equality of two types.
+--
+-- /Since: 4.19.0.0/
+hdecT :: forall a b. (Typeable a, Typeable b) => Either (a :~~: b -> Void) (a :~~: b)
+hdecT = ta `TR.decTypeRep` tb
+  where
+    ta = TR.typeRep :: TR.TypeRep a
+    tb = TR.typeRep :: TR.TypeRep b
+# endif
+#endif
diff --git a/src/Data/Typeable/Compat/Repl.hs b/src/Data/Typeable/Compat/Repl.hs
new file mode 100644
--- /dev/null
+++ b/src/Data/Typeable/Compat/Repl.hs
@@ -0,0 +1,8 @@
+{-# LANGUAGE PackageImports #-}
+{-# OPTIONS_GHC -Wno-dodgy-exports -Wno-unused-imports #-}
+-- | Reexports "Data.Typeable.Compat"
+-- from a globally unique namespace.
+module Data.Typeable.Compat.Repl (
+  module Data.Typeable.Compat
+) where
+import "this" Data.Typeable.Compat
diff --git a/src/Data/Version/Compat.hs b/src/Data/Version/Compat.hs
--- a/src/Data/Version/Compat.hs
+++ b/src/Data/Version/Compat.hs
@@ -1,16 +1,6 @@
-{-# LANGUAGE CPP, NoImplicitPrelude #-}
+{-# LANGUAGE NoImplicitPrelude #-}
 module Data.Version.Compat (
   module Base
 , makeVersion
 ) where
 import Data.Version as Base
-
-#if !(MIN_VERSION_base(4,8,0))
-import Prelude.Compat
-
--- | Construct tag-less 'Version'
---
--- /Since: 4.8.0.0/
-makeVersion :: [Int] -> Version
-makeVersion b = Version b []
-#endif
diff --git a/src/Data/Version/Compat/Repl.hs b/src/Data/Version/Compat/Repl.hs
--- a/src/Data/Version/Compat/Repl.hs
+++ b/src/Data/Version/Compat/Repl.hs
@@ -1,5 +1,5 @@
 {-# LANGUAGE PackageImports #-}
-{-# OPTIONS_GHC -fno-warn-dodgy-exports -fno-warn-unused-imports #-}
+{-# OPTIONS_GHC -Wno-dodgy-exports -Wno-unused-imports #-}
 -- | Reexports "Data.Version.Compat"
 -- from a globally unique namespace.
 module Data.Version.Compat.Repl (
diff --git a/src/Data/Void/Compat.hs b/src/Data/Void/Compat.hs
--- a/src/Data/Void/Compat.hs
+++ b/src/Data/Void/Compat.hs
@@ -1,10 +1,6 @@
-{-# LANGUAGE CPP, NoImplicitPrelude #-}
+{-# LANGUAGE NoImplicitPrelude #-}
 module Data.Void.Compat (
-#if MIN_VERSION_base(4,8,0)
   module Base
-#endif
 ) where
 
-#if MIN_VERSION_base(4,8,0)
 import Data.Void as Base
-#endif
diff --git a/src/Data/Void/Compat/Repl.hs b/src/Data/Void/Compat/Repl.hs
--- a/src/Data/Void/Compat/Repl.hs
+++ b/src/Data/Void/Compat/Repl.hs
@@ -1,5 +1,5 @@
 {-# LANGUAGE PackageImports #-}
-{-# OPTIONS_GHC -fno-warn-dodgy-exports -fno-warn-unused-imports #-}
+{-# OPTIONS_GHC -Wno-dodgy-exports -Wno-unused-imports #-}
 -- | Reexports "Data.Void.Compat"
 -- from a globally unique namespace.
 module Data.Void.Compat.Repl (
diff --git a/src/Data/Word/Compat.hs b/src/Data/Word/Compat.hs
--- a/src/Data/Word/Compat.hs
+++ b/src/Data/Word/Compat.hs
@@ -1,4 +1,4 @@
-{-# LANGUAGE CPP, NoImplicitPrelude #-}
+{-# LANGUAGE NoImplicitPrelude #-}
 module Data.Word.Compat (
   module Base
 , byteSwap16
@@ -7,36 +7,3 @@
 ) where
 
 import Data.Word as Base
-
-#if !(MIN_VERSION_base(4,7,0))
-import Data.Bits
-
--- | Swap bytes in 'Word16'.
---
--- /Since: 4.7.0.0/
-byteSwap16 :: Word16 -> Word16
-byteSwap16 w = ((w `shiftR` 8) .&. 0x00ff)
-           .|. ((w .&. 0x00ff) `shiftL` 8)
-
--- | Reverse order of bytes in 'Word32'.
---
--- /Since: 4.7.0.0/
-byteSwap32 :: Word32 -> Word32
-byteSwap32 w = ((w .&. 0xff000000) `shiftR` 24)
-           .|. ((w .&. 0x00ff0000) `shiftR` 8)
-           .|. ((w .&. 0x0000ff00) `shiftL` 8)
-           .|. ((w .&. 0x000000ff) `shiftL` 24)
-
--- | Reverse order of bytes in 'Word64'.
---
--- /Since: 4.7.0.0/
-byteSwap64 :: Word64 -> Word64
-byteSwap64 w = ((w .&. 0xff00000000000000) `shiftR` 56)
-           .|. ((w .&. 0x00ff000000000000) `shiftR` 40)
-           .|. ((w .&. 0x0000ff0000000000) `shiftR` 24)
-           .|. ((w .&. 0x000000ff00000000) `shiftR` 8)
-           .|. ((w .&. 0x00000000ff000000) `shiftL` 8)
-           .|. ((w .&. 0x0000000000ff0000) `shiftL` 24)
-           .|. ((w .&. 0x000000000000ff00) `shiftL` 40)
-           .|. ((w .&. 0x00000000000000ff) `shiftL` 56)
-#endif
diff --git a/src/Data/Word/Compat/Repl.hs b/src/Data/Word/Compat/Repl.hs
--- a/src/Data/Word/Compat/Repl.hs
+++ b/src/Data/Word/Compat/Repl.hs
@@ -1,5 +1,5 @@
 {-# LANGUAGE PackageImports #-}
-{-# OPTIONS_GHC -fno-warn-dodgy-exports -fno-warn-unused-imports #-}
+{-# OPTIONS_GHC -Wno-dodgy-exports -Wno-unused-imports #-}
 -- | Reexports "Data.Word.Compat"
 -- from a globally unique namespace.
 module Data.Word.Compat.Repl (
diff --git a/src/Debug/Trace/Compat.hs b/src/Debug/Trace/Compat.hs
--- a/src/Debug/Trace/Compat.hs
+++ b/src/Debug/Trace/Compat.hs
@@ -5,73 +5,47 @@
 , traceShowId
 , traceM
 , traceShowM
+, traceWith
+, traceShowWith
+, traceEventWith
 ) where
 
-#if !(MIN_VERSION_base(4,7,0)) || MIN_VERSION_base(4,9,0)
 import Debug.Trace as Base
-#else
-import Debug.Trace as Base hiding (
-    traceM
-  , traceShowM
-  )
-#endif
 
-#if !(MIN_VERSION_base(4,9,0))
+#if !(MIN_VERSION_base(4,18,0))
 import Prelude.Compat
 #endif
 
-#if !(MIN_VERSION_base(4,7,0))
+#if !(MIN_VERSION_base(4,18,0))
 {-|
-Like 'trace' but returns the message instead of a third value.
-
-/Since: 4.7.0.0/
--}
-traceId :: String -> String
-traceId a = trace a a
+Like 'trace', but outputs the result of calling a function on the argument.
 
-{-|
-Like 'traceShow' but returns the shown value instead of a third value.
+>>> traceWith fst ("hello","world")
+hello
+("hello","world")
 
-/Since: 4.7.0.0/
+/Since: 4.18.0.0/
 -}
-traceShowId :: (Show a) => a -> a
-traceShowId a = trace (show a) a
-#endif
+traceWith :: (a -> String) -> a -> a
+traceWith f a = trace (f a) a
 
-#if !(MIN_VERSION_base(4,9,0))
 {-|
-Like 'trace' but returning unit in an arbitrary 'Applicative' context. Allows
-for convenient use in do-notation.
-
-Note that the application of 'traceM' is not an action in the 'Applicative'
-context, as 'traceIO' is in the 'IO' type. While the fresh bindings in the
-following example will force the 'traceM' expressions to be reduced every time
-the @do@-block is executed, @traceM "not crashed"@ would only be reduced once,
-and the message would only be printed once.  If your monad is in 'MonadIO',
-@liftIO . traceIO@ may be a better option.
+Like 'traceWith', but uses 'show' on the result of the function to convert it to
+a 'String'.
 
-> ... = do
->   x <- ...
->   traceM $ "x: " ++ show x
->   y <- ...
->   traceM $ "y: " ++ show y
+>>> traceShowWith length [1,2,3]
+3
+[1,2,3]
 
-/Since: 4.7.0.0/
+/Since: 4.18.0.0/
 -}
-traceM :: (Applicative f) => String -> f ()
-traceM string = trace string $ pure ()
-
-{-|
-Like 'traceM', but uses 'show' on the argument to convert it to a 'String'.
-
-> ... = do
->   x <- ...
->   traceShowM $ x
->   y <- ...
->   traceShowM $ x + y
+traceShowWith :: Show b => (a -> b) -> a -> a
+traceShowWith f = traceWith (show . f)
 
-/Since: 4.7.0.0/
--}
-traceShowM :: (Show a, Applicative f) => a -> f ()
-traceShowM = traceM . show
+-- | Like 'traceEvent', but emits the result of calling a function on its
+-- argument.
+--
+-- /Since: 4.18.0.0/
+traceEventWith :: (a -> String) -> a -> a
+traceEventWith f a = traceEvent (f a) a
 #endif
diff --git a/src/Debug/Trace/Compat/Repl.hs b/src/Debug/Trace/Compat/Repl.hs
--- a/src/Debug/Trace/Compat/Repl.hs
+++ b/src/Debug/Trace/Compat/Repl.hs
@@ -1,5 +1,5 @@
 {-# LANGUAGE PackageImports #-}
-{-# OPTIONS_GHC -fno-warn-dodgy-exports -fno-warn-unused-imports #-}
+{-# OPTIONS_GHC -Wno-dodgy-exports -Wno-unused-imports #-}
 -- | Reexports "Debug.Trace.Compat"
 -- from a globally unique namespace.
 module Debug.Trace.Compat.Repl (
diff --git a/src/Foreign/Compat.hs b/src/Foreign/Compat.hs
--- a/src/Foreign/Compat.hs
+++ b/src/Foreign/Compat.hs
@@ -1,7 +1,5 @@
-{-# LANGUAGE CPP, NoImplicitPrelude #-}
-#if __GLASGOW_HASKELL__ >= 702
+{-# LANGUAGE NoImplicitPrelude #-}
 {-# LANGUAGE Trustworthy #-}
-#endif
 module Foreign.Compat (
   module Base
 , module Marshal
diff --git a/src/Foreign/Compat/Repl.hs b/src/Foreign/Compat/Repl.hs
--- a/src/Foreign/Compat/Repl.hs
+++ b/src/Foreign/Compat/Repl.hs
@@ -1,5 +1,5 @@
 {-# LANGUAGE PackageImports #-}
-{-# OPTIONS_GHC -fno-warn-dodgy-exports -fno-warn-unused-imports #-}
+{-# OPTIONS_GHC -Wno-dodgy-exports -Wno-unused-imports #-}
 -- | Reexports "Foreign.Compat"
 -- from a globally unique namespace.
 module Foreign.Compat.Repl (
diff --git a/src/Foreign/ForeignPtr/Compat.hs b/src/Foreign/ForeignPtr/Compat.hs
--- a/src/Foreign/ForeignPtr/Compat.hs
+++ b/src/Foreign/ForeignPtr/Compat.hs
@@ -1,8 +1,6 @@
 {-# LANGUAGE CPP, NoImplicitPrelude #-}
 {-# LANGUAGE MagicHash #-}
-#if __GLASGOW_HASKELL__ >= 702
 {-# LANGUAGE Trustworthy #-}
-#endif
 module Foreign.ForeignPtr.Compat (
   module Base
 , plusForeignPtr
diff --git a/src/Foreign/ForeignPtr/Compat/Repl.hs b/src/Foreign/ForeignPtr/Compat/Repl.hs
--- a/src/Foreign/ForeignPtr/Compat/Repl.hs
+++ b/src/Foreign/ForeignPtr/Compat/Repl.hs
@@ -1,5 +1,5 @@
 {-# LANGUAGE PackageImports #-}
-{-# OPTIONS_GHC -fno-warn-dodgy-exports -fno-warn-unused-imports #-}
+{-# OPTIONS_GHC -Wno-dodgy-exports -Wno-unused-imports #-}
 -- | Reexports "Foreign.ForeignPtr.Compat"
 -- from a globally unique namespace.
 module Foreign.ForeignPtr.Compat.Repl (
diff --git a/src/Foreign/ForeignPtr/Safe/Compat.hs b/src/Foreign/ForeignPtr/Safe/Compat.hs
--- a/src/Foreign/ForeignPtr/Safe/Compat.hs
+++ b/src/Foreign/ForeignPtr/Safe/Compat.hs
@@ -1,7 +1,5 @@
 {-# LANGUAGE CPP, NoImplicitPrelude #-}
-#if __GLASGOW_HASKELL__ >= 702
 {-# LANGUAGE Trustworthy #-}
-#endif
 module Foreign.ForeignPtr.Safe.Compat (
         -- * Finalised data pointers
           ForeignPtr
diff --git a/src/Foreign/ForeignPtr/Safe/Compat/Repl.hs b/src/Foreign/ForeignPtr/Safe/Compat/Repl.hs
--- a/src/Foreign/ForeignPtr/Safe/Compat/Repl.hs
+++ b/src/Foreign/ForeignPtr/Safe/Compat/Repl.hs
@@ -1,5 +1,5 @@
 {-# LANGUAGE PackageImports #-}
-{-# OPTIONS_GHC -fno-warn-dodgy-exports -fno-warn-unused-imports #-}
+{-# OPTIONS_GHC -Wno-dodgy-exports -Wno-unused-imports #-}
 -- | Reexports "Foreign.ForeignPtr.Safe.Compat"
 -- from a globally unique namespace.
 module Foreign.ForeignPtr.Safe.Compat.Repl (
diff --git a/src/Foreign/ForeignPtr/Unsafe/Compat.hs b/src/Foreign/ForeignPtr/Unsafe/Compat.hs
--- a/src/Foreign/ForeignPtr/Unsafe/Compat.hs
+++ b/src/Foreign/ForeignPtr/Unsafe/Compat.hs
@@ -1,11 +1,7 @@
-{-# LANGUAGE CPP, NoImplicitPrelude #-}
+{-# LANGUAGE NoImplicitPrelude #-}
 module Foreign.ForeignPtr.Unsafe.Compat (
   -- ** Unsafe low-level operations
   unsafeForeignPtrToPtr
 ) where
 
-#if MIN_VERSION_base(4,6,0)
 import Foreign.ForeignPtr.Unsafe (unsafeForeignPtrToPtr)
-#else
-import Foreign.ForeignPtr (unsafeForeignPtrToPtr)
-#endif
diff --git a/src/Foreign/ForeignPtr/Unsafe/Compat/Repl.hs b/src/Foreign/ForeignPtr/Unsafe/Compat/Repl.hs
--- a/src/Foreign/ForeignPtr/Unsafe/Compat/Repl.hs
+++ b/src/Foreign/ForeignPtr/Unsafe/Compat/Repl.hs
@@ -1,5 +1,5 @@
 {-# LANGUAGE PackageImports #-}
-{-# OPTIONS_GHC -fno-warn-dodgy-exports -fno-warn-unused-imports #-}
+{-# OPTIONS_GHC -Wno-dodgy-exports -Wno-unused-imports #-}
 -- | Reexports "Foreign.ForeignPtr.Unsafe.Compat"
 -- from a globally unique namespace.
 module Foreign.ForeignPtr.Unsafe.Compat.Repl (
diff --git a/src/Foreign/Marshal/Alloc/Compat.hs b/src/Foreign/Marshal/Alloc/Compat.hs
--- a/src/Foreign/Marshal/Alloc/Compat.hs
+++ b/src/Foreign/Marshal/Alloc/Compat.hs
@@ -1,4 +1,4 @@
-{-# LANGUAGE CPP, NoImplicitPrelude #-}
+{-# LANGUAGE NoImplicitPrelude #-}
 {-# LANGUAGE ForeignFunctionInterface #-}
 module Foreign.Marshal.Alloc.Compat (
   module Base
@@ -6,38 +6,3 @@
 , callocBytes
 ) where
 import Foreign.Marshal.Alloc as Base
-
-#if !(MIN_VERSION_base(4,8,0))
-import Foreign.C.Types
-import Foreign.Ptr (Ptr, nullPtr)
-import Foreign.Storable (Storable(..))
-import GHC.IO.Exception
-import Prelude.Compat
-
--- |Like 'malloc' but memory is filled with bytes of value zero.
---
-{-# INLINE calloc #-}
-calloc :: Storable a => IO (Ptr a)
-calloc = doCalloc undefined
-  where
-    doCalloc       :: Storable b => b -> IO (Ptr b)
-    doCalloc dummy = callocBytes (sizeOf dummy)
-
--- |Llike 'mallocBytes' but memory is filled with bytes of value zero.
---
-callocBytes :: Int -> IO (Ptr a)
-callocBytes size = failWhenNULL "calloc" $ _calloc 1 (fromIntegral size)
-
--- asserts that the pointer returned from the action in the second argument is
--- non-null
---
-failWhenNULL :: String -> IO (Ptr a) -> IO (Ptr a)
-failWhenNULL name f = do
-   addr <- f
-   if addr == nullPtr
-      then ioError (IOError Nothing ResourceExhausted name
-                                        "out of memory" Nothing Nothing)
-      else return addr
-
-foreign import ccall unsafe "stdlib.h calloc"  _calloc  :: CSize -> CSize -> IO (Ptr a)
-#endif
diff --git a/src/Foreign/Marshal/Alloc/Compat/Repl.hs b/src/Foreign/Marshal/Alloc/Compat/Repl.hs
--- a/src/Foreign/Marshal/Alloc/Compat/Repl.hs
+++ b/src/Foreign/Marshal/Alloc/Compat/Repl.hs
@@ -1,5 +1,5 @@
 {-# LANGUAGE PackageImports #-}
-{-# OPTIONS_GHC -fno-warn-dodgy-exports -fno-warn-unused-imports #-}
+{-# OPTIONS_GHC -Wno-dodgy-exports -Wno-unused-imports #-}
 -- | Reexports "Foreign.Marshal.Alloc.Compat"
 -- from a globally unique namespace.
 module Foreign.Marshal.Alloc.Compat.Repl (
diff --git a/src/Foreign/Marshal/Array/Compat.hs b/src/Foreign/Marshal/Array/Compat.hs
--- a/src/Foreign/Marshal/Array/Compat.hs
+++ b/src/Foreign/Marshal/Array/Compat.hs
@@ -1,28 +1,7 @@
-{-# LANGUAGE CPP, NoImplicitPrelude #-}
+{-# LANGUAGE NoImplicitPrelude #-}
 module Foreign.Marshal.Array.Compat (
   module Base
 , callocArray
 , callocArray0
 ) where
 import Foreign.Marshal.Array as Base
-
-#if !(MIN_VERSION_base(4,8,0))
-import Foreign.Marshal.Alloc.Compat
-import Foreign.Ptr (Ptr)
-import Foreign.Storable (Storable(..))
-import Prelude.Compat
-
--- |Like 'mallocArray', but allocated memory is filled with bytes of value zero.
---
-callocArray :: Storable a => Int -> IO (Ptr a)
-callocArray  = doCalloc undefined
-  where
-    doCalloc :: Storable a' => a' -> Int -> IO (Ptr a')
-    doCalloc dummy size  = callocBytes (size * sizeOf dummy)
-
--- |Like 'callocArray0', but allocated memory is filled with bytes of value
--- zero.
---
-callocArray0 :: Storable a => Int -> IO (Ptr a)
-callocArray0 size  = callocArray (size + 1)
-#endif
diff --git a/src/Foreign/Marshal/Array/Compat/Repl.hs b/src/Foreign/Marshal/Array/Compat/Repl.hs
--- a/src/Foreign/Marshal/Array/Compat/Repl.hs
+++ b/src/Foreign/Marshal/Array/Compat/Repl.hs
@@ -1,5 +1,5 @@
 {-# LANGUAGE PackageImports #-}
-{-# OPTIONS_GHC -fno-warn-dodgy-exports -fno-warn-unused-imports #-}
+{-# OPTIONS_GHC -Wno-dodgy-exports -Wno-unused-imports #-}
 -- | Reexports "Foreign.Marshal.Array.Compat"
 -- from a globally unique namespace.
 module Foreign.Marshal.Array.Compat.Repl (
diff --git a/src/Foreign/Marshal/Compat.hs b/src/Foreign/Marshal/Compat.hs
--- a/src/Foreign/Marshal/Compat.hs
+++ b/src/Foreign/Marshal/Compat.hs
@@ -1,7 +1,5 @@
-{-# LANGUAGE CPP, NoImplicitPrelude #-}
-#if __GLASGOW_HASKELL__ >= 702
+{-# LANGUAGE NoImplicitPrelude #-}
 {-# LANGUAGE Trustworthy #-}
-#endif
 module Foreign.Marshal.Compat (
   module Base
 , module Alloc
diff --git a/src/Foreign/Marshal/Compat/Repl.hs b/src/Foreign/Marshal/Compat/Repl.hs
--- a/src/Foreign/Marshal/Compat/Repl.hs
+++ b/src/Foreign/Marshal/Compat/Repl.hs
@@ -1,5 +1,5 @@
 {-# LANGUAGE PackageImports #-}
-{-# OPTIONS_GHC -fno-warn-dodgy-exports -fno-warn-unused-imports #-}
+{-# OPTIONS_GHC -Wno-dodgy-exports -Wno-unused-imports #-}
 -- | Reexports "Foreign.Marshal.Compat"
 -- from a globally unique namespace.
 module Foreign.Marshal.Compat.Repl (
diff --git a/src/Foreign/Marshal/Safe/Compat/Repl.hs b/src/Foreign/Marshal/Safe/Compat/Repl.hs
--- a/src/Foreign/Marshal/Safe/Compat/Repl.hs
+++ b/src/Foreign/Marshal/Safe/Compat/Repl.hs
@@ -1,5 +1,5 @@
 {-# LANGUAGE PackageImports #-}
-{-# OPTIONS_GHC -fno-warn-dodgy-exports -fno-warn-unused-imports #-}
+{-# OPTIONS_GHC -Wno-dodgy-exports -Wno-unused-imports #-}
 -- | Reexports "Foreign.Marshal.Safe.Compat"
 -- from a globally unique namespace.
 module Foreign.Marshal.Safe.Compat.Repl (
diff --git a/src/Foreign/Marshal/Unsafe/Compat.hs b/src/Foreign/Marshal/Unsafe/Compat.hs
--- a/src/Foreign/Marshal/Unsafe/Compat.hs
+++ b/src/Foreign/Marshal/Unsafe/Compat.hs
@@ -1,11 +1,7 @@
-{-# LANGUAGE CPP, NoImplicitPrelude #-}
+{-# LANGUAGE NoImplicitPrelude #-}
 module Foreign.Marshal.Unsafe.Compat (
   -- * Unsafe functions
   unsafeLocalState
 ) where
 
-#if MIN_VERSION_base(4,6,0)
 import Foreign.Marshal.Unsafe (unsafeLocalState)
-#else
-import Foreign.Marshal (unsafeLocalState)
-#endif
diff --git a/src/Foreign/Marshal/Unsafe/Compat/Repl.hs b/src/Foreign/Marshal/Unsafe/Compat/Repl.hs
--- a/src/Foreign/Marshal/Unsafe/Compat/Repl.hs
+++ b/src/Foreign/Marshal/Unsafe/Compat/Repl.hs
@@ -1,5 +1,5 @@
 {-# LANGUAGE PackageImports #-}
-{-# OPTIONS_GHC -fno-warn-dodgy-exports -fno-warn-unused-imports #-}
+{-# OPTIONS_GHC -Wno-dodgy-exports -Wno-unused-imports #-}
 -- | Reexports "Foreign.Marshal.Unsafe.Compat"
 -- from a globally unique namespace.
 module Foreign.Marshal.Unsafe.Compat.Repl (
diff --git a/src/Foreign/Marshal/Utils/Compat.hs b/src/Foreign/Marshal/Utils/Compat.hs
--- a/src/Foreign/Marshal/Utils/Compat.hs
+++ b/src/Foreign/Marshal/Utils/Compat.hs
@@ -1,4 +1,4 @@
-{-# LANGUAGE CPP, NoImplicitPrelude #-}
+{-# LANGUAGE NoImplicitPrelude #-}
 {-# LANGUAGE ForeignFunctionInterface #-}
 module Foreign.Marshal.Utils.Compat (
   module Base
@@ -6,20 +6,3 @@
 ) where
 
 import Foreign.Marshal.Utils as Base
-
-#if !(MIN_VERSION_base(4,8,0))
-import Data.Word (Word8)
-import Foreign.C.Types
-import Foreign.Ptr
-import Prelude
-
--- |Fill a given number of bytes in memory area with a byte value.
---
--- /Since: 4.8.0.0/
-fillBytes :: Ptr a -> Word8 -> Int -> IO ()
-fillBytes dest char size = do
-  _ <- memset dest (fromIntegral char) (fromIntegral size)
-  return ()
-
-foreign import ccall unsafe "string.h" memset :: Ptr a -> CInt -> CSize -> IO (Ptr a)
-#endif
diff --git a/src/Foreign/Marshal/Utils/Compat/Repl.hs b/src/Foreign/Marshal/Utils/Compat/Repl.hs
--- a/src/Foreign/Marshal/Utils/Compat/Repl.hs
+++ b/src/Foreign/Marshal/Utils/Compat/Repl.hs
@@ -1,5 +1,5 @@
 {-# LANGUAGE PackageImports #-}
-{-# OPTIONS_GHC -fno-warn-dodgy-exports -fno-warn-unused-imports #-}
+{-# OPTIONS_GHC -Wno-dodgy-exports -Wno-unused-imports #-}
 -- | Reexports "Foreign.Marshal.Utils.Compat"
 -- from a globally unique namespace.
 module Foreign.Marshal.Utils.Compat.Repl (
diff --git a/src/Numeric/Compat.hs b/src/Numeric/Compat.hs
--- a/src/Numeric/Compat.hs
+++ b/src/Numeric/Compat.hs
@@ -1,107 +1,20 @@
 {-# LANGUAGE CPP, NoImplicitPrelude #-}
 module Numeric.Compat (
   module Base
+, showBin
 , showFFloatAlt
 , showGFloatAlt
 , showHFloat
+, readBin
 ) where
 
 import Numeric as Base
 
-#if !(MIN_VERSION_base(4,7,0))
+#if !(MIN_VERSION_base(4,16,0))
 import Data.Char (intToDigit)
-import GHC.Float
-#endif
-
-#if !(MIN_VERSION_base(4,11,0))
 import Prelude
-#endif
-
-#if !(MIN_VERSION_base(4,7,0))
--- | Show a signed 'RealFloat' value
--- using standard decimal notation (e.g. @245000@, @0.0015@).
---
--- This behaves as 'showFFloat', except that a decimal point
--- is always guaranteed, even if not needed.
---
--- /Since: 4.7.0.0/
-showFFloatAlt    :: (RealFloat a) => Maybe Int -> a -> ShowS
-showFFloatAlt d x = showString (formatRealFloatAlt FFFixed d True x)
-
--- | Show a signed 'RealFloat' value
--- using standard decimal notation for arguments whose absolute value lies
--- between @0.1@ and @9,999,999@, and scientific notation otherwise.
---
--- This behaves as 'showFFloat', except that a decimal point
--- is always guaranteed, even if not needed.
---
--- /Since: 4.7.0.0/
-showGFloatAlt :: (RealFloat a) => Maybe Int -> a -> ShowS
-showGFloatAlt d x = showString (formatRealFloatAlt FFGeneric d True x)
-
-formatRealFloatAlt :: (RealFloat a) => FFFormat -> Maybe Int -> Bool -> a
-                 -> String
-formatRealFloatAlt fmt decs alt x
-   | isNaN x                   = "NaN"
-   | isInfinite x              = if x < 0 then "-Infinity" else "Infinity"
-   | x < 0 || isNegativeZero x = '-':doFmt fmt (floatToDigits (toInteger base) (-x))
-   | otherwise                 = doFmt fmt (floatToDigits (toInteger base) x)
- where
-  base = 10
-
-  doFmt format (is, e) =
-    let ds = map intToDigit is in
-    case format of
-     FFGeneric ->
-      doFmt (if e < 0 || e > 7 then FFExponent else FFFixed)
-            (is,e)
-     FFExponent ->
-      case decs of
-       Nothing ->
-        let show_e' = show (e-1) in
-        case ds of
-          "0"     -> "0.0e0"
-          [d]     -> d : ".0e" ++ show_e'
-          (d:ds') -> d : '.' : ds' ++ "e" ++ show_e'
-          []      -> error "formatRealFloat/doFmt/FFExponent: []"
-       Just dec ->
-        let dec' = max dec 1 in
-        case is of
-         [0] -> '0' :'.' : take dec' (repeat '0') ++ "e0"
-         _ ->
-          let
-           (ei,is') = roundTo base (dec'+1) is
-           (d:ds') = map intToDigit (if ei > 0 then init is' else is')
-          in
-          d:'.':ds' ++ 'e':show (e-1+ei)
-     FFFixed ->
-      let
-       mk0 ls = case ls of { "" -> "0" ; _ -> ls}
-      in
-      case decs of
-       Nothing
-          | e <= 0    -> "0." ++ replicate (-e) '0' ++ ds
-          | otherwise ->
-             let
-                f 0 s    rs  = mk0 (reverse s) ++ '.':mk0 rs
-                f n s    ""  = f (n-1) ('0':s) ""
-                f n s (r:rs) = f (n-1) (r:s) rs
-             in
-                f e "" ds
-       Just dec ->
-        let dec' = max dec 0 in
-        if e >= 0 then
-         let
-          (ei,is') = roundTo base (dec' + e) is
-          (ls,rs)  = splitAt (e+ei) (map intToDigit is')
-         in
-         mk0 ls ++ (if null rs && not alt then "" else '.':rs)
-        else
-         let
-          (ei,is') = roundTo base dec' (replicate (-e) 0 ++ is)
-          d:ds' = map intToDigit (if ei > 0 then is' else 0:is')
-         in
-         d : (if null ds' && not alt then "" else '.':ds')
+import Text.ParserCombinators.ReadP (readP_to_S)
+import qualified Text.Read.Lex.Compat as L
 #endif
 
 #if !(MIN_VERSION_base(4,11,0))
@@ -150,4 +63,17 @@
   allZ xs = case xs of
               x : more -> x == 0 && allZ more
               []       -> True
+#endif
+
+#if !(MIN_VERSION_base(4,16,0))
+-- | Read an unsigned number in binary notation.
+--
+-- >>> readBin "10011"
+-- [(19,"")]
+readBin :: (Eq a, Num a) => ReadS a
+readBin = readP_to_S L.readBinP
+
+-- | Show /non-negative/ 'Integral' numbers in base 2.
+showBin :: (Integral a, Show a) => a -> ShowS
+showBin = showIntAtBase 2  intToDigit
 #endif
diff --git a/src/Numeric/Compat/Repl.hs b/src/Numeric/Compat/Repl.hs
--- a/src/Numeric/Compat/Repl.hs
+++ b/src/Numeric/Compat/Repl.hs
@@ -1,5 +1,5 @@
 {-# LANGUAGE PackageImports #-}
-{-# OPTIONS_GHC -fno-warn-dodgy-exports -fno-warn-unused-imports #-}
+{-# OPTIONS_GHC -Wno-dodgy-exports -Wno-unused-imports #-}
 -- | Reexports "Numeric.Compat"
 -- from a globally unique namespace.
 module Numeric.Compat.Repl (
diff --git a/src/Numeric/Natural/Compat.hs b/src/Numeric/Natural/Compat.hs
--- a/src/Numeric/Natural/Compat.hs
+++ b/src/Numeric/Natural/Compat.hs
@@ -1,10 +1,12 @@
 {-# LANGUAGE CPP, NoImplicitPrelude #-}
+{-# LANGUAGE Trustworthy #-}
 module Numeric.Natural.Compat (
-#if MIN_VERSION_base(4,8,0)
   module Base
-#endif
+, minusNaturalMaybe
 ) where
 
-#if MIN_VERSION_base(4,8,0)
 import Numeric.Natural as Base
+
+#if !(MIN_VERSION_base(4,18,0))
+import GHC.Natural (minusNaturalMaybe)
 #endif
diff --git a/src/Numeric/Natural/Compat/Repl.hs b/src/Numeric/Natural/Compat/Repl.hs
--- a/src/Numeric/Natural/Compat/Repl.hs
+++ b/src/Numeric/Natural/Compat/Repl.hs
@@ -1,5 +1,5 @@
 {-# LANGUAGE PackageImports #-}
-{-# OPTIONS_GHC -fno-warn-dodgy-exports -fno-warn-unused-imports #-}
+{-# OPTIONS_GHC -Wno-dodgy-exports -Wno-unused-imports #-}
 -- | Reexports "Numeric.Natural.Compat"
 -- from a globally unique namespace.
 module Numeric.Natural.Compat.Repl (
diff --git a/src/Prelude/Compat.hs b/src/Prelude/Compat.hs
--- a/src/Prelude/Compat.hs
+++ b/src/Prelude/Compat.hs
@@ -1,14 +1,15 @@
 {-# LANGUAGE CPP, NoImplicitPrelude #-}
-#if __GLASGOW_HASKELL__ >= 702
 {-# LANGUAGE Trustworthy #-}
-#endif
 #if MIN_VERSION_base(4,10,0) && !(MIN_VERSION_base(4,12,0))
 {-# LANGUAGE BangPatterns #-}
 {-# LANGUAGE RankNTypes #-}
 {-# LANGUAGE TypeInType #-}
 #endif
+#if MIN_VERSION_base(4,17,0) && !(MIN_VERSION_base(4,20,0))
+{-# LANGUAGE ExplicitNamespaces #-}
+#endif
 module Prelude.Compat (
-#if MIN_VERSION_base(4,12,0)
+#if MIN_VERSION_base(4,20,0)
   module Base
 #else
   either
@@ -116,6 +117,7 @@
 , elem
 , foldMap
 , foldl
+, foldl'
 , foldl1
 , foldr
 , foldr1
@@ -133,6 +135,7 @@
 , (<*)
 , (<*>)
 , pure
+, liftA2
 , (<$)
 , fmap
 , (>>)
@@ -142,9 +145,7 @@
 , mappend
 , mconcat
 , mempty
-# if MIN_VERSION_base(4,9,0)
 , (<>)
-# endif
 , maxBound
 , minBound
 , enumFrom
@@ -235,9 +236,7 @@
 , Functor
 , Integral
 , Monad
-#if MIN_VERSION_base(4,9,0)
 , MonadFail
-#endif
 , Monoid
 , Num (fromInteger)
 , Ord
@@ -245,9 +244,7 @@
 , Real
 , RealFloat
 , RealFrac
-# if MIN_VERSION_base(4,9,0)
 , Semigroup
-# endif
 , Show
 , Traversable
 
@@ -271,79 +268,42 @@
 , ReadS
 , ShowS
 , String
+
+# if MIN_VERSION_base(4,17,0)
+-- The equality types
+, type (~)
+# endif
 #endif
 ) where
 
 
-#if MIN_VERSION_base(4,9,0)
-
 import Prelude as Base hiding (
-# if !(MIN_VERSION_base(4,13,0))
+#if !(MIN_VERSION_base(4,13,0))
     fail
-#  if MIN_VERSION_base(4,10,0) && !(MIN_VERSION_base(4,12,0))
+# if MIN_VERSION_base(4,10,0) && !(MIN_VERSION_base(4,12,0))
   , ($!)
-#  endif
 # endif
-  )
-
-#else
-
-import Prelude hiding (
-    length
-  , null
-  , foldr
-  , mapM
-  , sequence
-  , all
-  , and
-  , any
-  , concat
-  , concatMap
-  , mapM
-  , mapM_
-  , notElem
-  , or
-  , sequence
-  , sequence_
-  , elem
-  , foldl
-  , foldl1
-  , foldr1
-  , maximum
-  , minimum
-  , product
-  , sum
+#endif
   )
 
-import Data.Foldable.Compat
-import Data.Traversable
+#if !(MIN_VERSION_base(4,18,0))
+import Control.Applicative (liftA2)
+#endif
 
-# if !(MIN_VERSION_base(4,8,0))
-import Control.Applicative
-import Data.Monoid
-import Data.Word
-# endif
+#if !(MIN_VERSION_base(4,20,0))
+import Data.Foldable (foldl')
 #endif
 
-#if MIN_VERSION_base(4,9,0) && !(MIN_VERSION_base(4,11,0))
+#if !(MIN_VERSION_base(4,11,0))
 import Data.Semigroup as Base (Semigroup((<>)))
 #endif
 
-#if MIN_VERSION_base(4,9,0) && !(MIN_VERSION_base(4,13,0))
+#if !(MIN_VERSION_base(4,13,0))
 import Control.Monad.Fail as Base (MonadFail(fail))
 #endif
 
 #if MIN_VERSION_base(4,10,0) && !(MIN_VERSION_base(4,12,0))
 import GHC.Exts (TYPE)
-#endif
-
-#if !(MIN_VERSION_base(4,9,0))
--- | A variant of 'error' that does not produce a stack trace.
---
--- /Since: 4.9.0.0/
-errorWithoutStackTrace :: [Char] -> a
-errorWithoutStackTrace s = error s
-{-# NOINLINE errorWithoutStackTrace #-}
 #endif
 
 #if MIN_VERSION_base(4,10,0) && !(MIN_VERSION_base(4,12,0))
diff --git a/src/Prelude/Compat/Repl.hs b/src/Prelude/Compat/Repl.hs
--- a/src/Prelude/Compat/Repl.hs
+++ b/src/Prelude/Compat/Repl.hs
@@ -1,5 +1,5 @@
 {-# LANGUAGE PackageImports #-}
-{-# OPTIONS_GHC -fno-warn-dodgy-exports -fno-warn-unused-imports #-}
+{-# OPTIONS_GHC -Wno-dodgy-exports -Wno-unused-imports #-}
 -- | Reexports "Prelude.Compat"
 -- from a globally unique namespace.
 module Prelude.Compat.Repl (
diff --git a/src/System/Environment/Compat.hs b/src/System/Environment/Compat.hs
--- a/src/System/Environment/Compat.hs
+++ b/src/System/Environment/Compat.hs
@@ -1,4 +1,4 @@
-{-# LANGUAGE CPP, NoImplicitPrelude #-}
+{-# LANGUAGE NoImplicitPrelude #-}
 {-# LANGUAGE ForeignFunctionInterface #-}
 -- | Miscellaneous information about the system environment.
 module System.Environment.Compat (
@@ -14,122 +14,3 @@
 ) where
 
 import           System.Environment
-
-#if !(MIN_VERSION_base(4,7,0))
-import           Prelude.Compat
-
-# ifdef mingw32_HOST_OS
-import           Control.Monad
-import           Foreign.C
-import           Foreign.Safe
-import           GHC.Windows
-# else
-import qualified System.Posix.Env as Posix
-# endif
-
-# ifdef mingw32_HOST_OS
-
-#  if defined(i386_HOST_ARCH)
-#   define WINDOWS_CCONV stdcall
-#  elif defined(x86_64_HOST_ARCH)
-#   define WINDOWS_CCONV ccall
-#  else
-#   error Unknown mingw32 arch
-#  endif
-
-foreign import WINDOWS_CCONV unsafe "windows.h GetLastError"
-  c_GetLastError:: IO DWORD
-
-eRROR_ENVVAR_NOT_FOUND :: DWORD
-eRROR_ENVVAR_NOT_FOUND = 203
-
-# endif
-
-# if !(MIN_VERSION_base(4,6,0))
--- | Return the value of the environment variable @var@, or @Nothing@ if
--- there is no such value.
---
--- For POSIX users, this is equivalent to 'System.Posix.Env.getEnv'.
-lookupEnv :: String -> IO (Maybe String)
-lookupEnv k = lookup k `fmap` getEnvironment
-# endif
-
--- | @setEnv name value@ sets the specified environment variable to @value@.
---
--- On Windows setting an environment variable to the /empty string/ removes
--- that environment variable from the environment.  For the sake of
--- compatibility we adopt that behavior.  In particular
---
--- @
--- setEnv name \"\"
--- @
---
--- has the same effect as
---
--- @
--- `unsetEnv` name
--- @
---
--- If you don't care about Windows support and want to set an environment
--- variable to the empty string use @System.Posix.Env.setEnv@ from the @unix@
--- package instead.
---
--- Throws `Control.Exception.IOException` if @name@ is the empty string or
--- contains an equals sign.
--- 
--- Note that setting Unicode values may not work correctly on versions of GHC
--- prior to 7.2.
-setEnv :: String -> String -> IO ()
-setEnv key value_
-  | null value = unsetEnv key
-  | otherwise  = setEnv_ key value
-  where
-    -- NOTE: Anything that follows NUL is ignored on both POSIX and Windows.
-    -- We still strip it manually so that the null check above succeds if a
-    -- value starts with NUL, and `unsetEnv` is called.  This is important for
-    -- two reasons.
-    --
-    --  * On POSIX setting an environment variable to the empty string does not
-    --    remove it.
-    --
-    --  * On Windows setting an environment variable to the empty string
-    --    removes that environment variable.  A subsequent call to
-    --    GetEnvironmentVariable will then return 0, but the calling thread's
-    --    last-error code will not be updated, and hence a call to GetLastError
-    --    may not return ERROR_ENVVAR_NOT_FOUND.  The failed lookup will then
-    --    result in a random error instead of the expected
-    --    `isDoesNotExistError` (this is at least true for Windows XP, SP 3).
-    --    Explicitly calling `unsetEnv` prevents this.
-    value = takeWhile (/= '\NUL') value_
-
-setEnv_ :: String -> String -> IO ()
-# ifdef mingw32_HOST_OS
-setEnv_ key value = withCWString key $ \k -> withCWString value $ \v -> do
-  success <- c_SetEnvironmentVariable k v
-  unless success (throwGetLastError "setEnv")
-
-foreign import WINDOWS_CCONV unsafe "windows.h SetEnvironmentVariableW"
-  c_SetEnvironmentVariable :: LPTSTR -> LPTSTR -> IO Bool
-# else
-setEnv_ k v = Posix.setEnv k v True
-# endif
-
--- | @unsetEnv name@ removes the specified environment variable from the
--- environment of the current process.
---
--- Throws `Control.Exception.IOException` if @name@ is the empty string or
--- contains an equals sign.
-unsetEnv :: String -> IO ()
-# ifdef mingw32_HOST_OS
-unsetEnv key = withCWString key $ \k -> do
-  success <- c_SetEnvironmentVariable k nullPtr
-  unless success $ do
-    -- We consider unsetting an environment variable that does not exist not as
-    -- an error, hence we ignore eRROR_ENVVAR_NOT_FOUND.
-    err <- c_GetLastError
-    unless (err == eRROR_ENVVAR_NOT_FOUND) $ do
-      throwGetLastError "unsetEnv"
-# else
-unsetEnv = Posix.unsetEnv
-# endif
-#endif
diff --git a/src/System/Environment/Compat/Repl.hs b/src/System/Environment/Compat/Repl.hs
--- a/src/System/Environment/Compat/Repl.hs
+++ b/src/System/Environment/Compat/Repl.hs
@@ -1,5 +1,5 @@
 {-# LANGUAGE PackageImports #-}
-{-# OPTIONS_GHC -fno-warn-dodgy-exports -fno-warn-unused-imports #-}
+{-# OPTIONS_GHC -Wno-dodgy-exports -Wno-unused-imports #-}
 -- | Reexports "System.Environment.Compat"
 -- from a globally unique namespace.
 module System.Environment.Compat.Repl (
diff --git a/src/System/Exit/Compat.hs b/src/System/Exit/Compat.hs
--- a/src/System/Exit/Compat.hs
+++ b/src/System/Exit/Compat.hs
@@ -1,20 +1,7 @@
-{-# LANGUAGE CPP, NoImplicitPrelude #-}
-{-# LANGUAGE CPP #-}
+{-# LANGUAGE NoImplicitPrelude #-}
 module System.Exit.Compat (
   module Base
 , die
 ) where
 
 import System.Exit as Base
-
-#if !(MIN_VERSION_base(4,8,0))
-
-import Prelude.Compat
-import System.IO
-
--- | Write given error message to `stderr` and terminate with `exitFailure`.
---
--- @since 4.8.0.0
-die :: String -> IO a
-die err = hPutStrLn stderr err >> exitFailure
-#endif
diff --git a/src/System/Exit/Compat/Repl.hs b/src/System/Exit/Compat/Repl.hs
--- a/src/System/Exit/Compat/Repl.hs
+++ b/src/System/Exit/Compat/Repl.hs
@@ -1,5 +1,5 @@
 {-# LANGUAGE PackageImports #-}
-{-# OPTIONS_GHC -fno-warn-dodgy-exports -fno-warn-unused-imports #-}
+{-# OPTIONS_GHC -Wno-dodgy-exports -Wno-unused-imports #-}
 -- | Reexports "System.Exit.Compat"
 -- from a globally unique namespace.
 module System.Exit.Compat.Repl (
diff --git a/src/System/IO/Compat/Repl.hs b/src/System/IO/Compat/Repl.hs
--- a/src/System/IO/Compat/Repl.hs
+++ b/src/System/IO/Compat/Repl.hs
@@ -1,5 +1,5 @@
 {-# LANGUAGE PackageImports #-}
-{-# OPTIONS_GHC -fno-warn-dodgy-exports -fno-warn-unused-imports #-}
+{-# OPTIONS_GHC -Wno-dodgy-exports -Wno-unused-imports #-}
 -- | Reexports "System.IO.Compat"
 -- from a globally unique namespace.
 module System.IO.Compat.Repl (
diff --git a/src/System/IO/Error/Compat/Repl.hs b/src/System/IO/Error/Compat/Repl.hs
--- a/src/System/IO/Error/Compat/Repl.hs
+++ b/src/System/IO/Error/Compat/Repl.hs
@@ -1,5 +1,5 @@
 {-# LANGUAGE PackageImports #-}
-{-# OPTIONS_GHC -fno-warn-dodgy-exports -fno-warn-unused-imports #-}
+{-# OPTIONS_GHC -Wno-dodgy-exports -Wno-unused-imports #-}
 -- | Reexports "System.IO.Error.Compat"
 -- from a globally unique namespace.
 module System.IO.Error.Compat.Repl (
diff --git a/src/System/IO/Unsafe/Compat.hs b/src/System/IO/Unsafe/Compat.hs
--- a/src/System/IO/Unsafe/Compat.hs
+++ b/src/System/IO/Unsafe/Compat.hs
@@ -1,4 +1,4 @@
-{-# LANGUAGE CPP, NoImplicitPrelude #-}
+{-# LANGUAGE NoImplicitPrelude #-}
 module System.IO.Unsafe.Compat (
   module Base
 , unsafeFixIO
@@ -6,30 +6,3 @@
 ) where
 
 import System.IO.Unsafe as Base
-
-#if !(MIN_VERSION_base(4,5,0))
-import Control.Exception
-import Data.IORef
-import GHC.Base
-import GHC.IO
-
--- | A slightly faster version of `System.IO.fixIO` that may not be
--- safe to use with multiple threads.  The unsafety arises when used
--- like this:
---
--- >  unsafeFixIO $ \r -> do
--- >     forkIO (print r)
--- >     return (...)
---
--- In this case, the child thread will receive a @NonTermination@
--- exception instead of waiting for the value of @r@ to be computed.
---
--- /Since: 4.5.0.0/
-unsafeFixIO :: (a -> IO a) -> IO a
-unsafeFixIO k = do
-  ref <- newIORef (throw NonTermination)
-  ans <- unsafeDupableInterleaveIO (readIORef ref)
-  result <- k ans
-  writeIORef ref result
-  return result
-#endif
diff --git a/src/System/IO/Unsafe/Compat/Repl.hs b/src/System/IO/Unsafe/Compat/Repl.hs
--- a/src/System/IO/Unsafe/Compat/Repl.hs
+++ b/src/System/IO/Unsafe/Compat/Repl.hs
@@ -1,5 +1,5 @@
 {-# LANGUAGE PackageImports #-}
-{-# OPTIONS_GHC -fno-warn-dodgy-exports -fno-warn-unused-imports #-}
+{-# OPTIONS_GHC -Wno-dodgy-exports -Wno-unused-imports #-}
 -- | Reexports "System.IO.Unsafe.Compat"
 -- from a globally unique namespace.
 module System.IO.Unsafe.Compat.Repl (
diff --git a/src/Text/Read/Compat.hs b/src/Text/Read/Compat.hs
--- a/src/Text/Read/Compat.hs
+++ b/src/Text/Read/Compat.hs
@@ -1,4 +1,4 @@
-{-# LANGUAGE CPP, NoImplicitPrelude #-}
+{-# LANGUAGE NoImplicitPrelude #-}
 module Text.Read.Compat (
    -- * The 'Read' class
    Read(..),
@@ -25,34 +25,3 @@
 import Text.Read
 import Text.ParserCombinators.ReadPrec
 import qualified Text.Read.Lex as L
-
-#if !(MIN_VERSION_base(4,6,0))
-import Prelude.Compat
-import qualified Text.ParserCombinators.ReadP as P
-
--- | Parse a string using the 'Read' instance.
--- Succeeds if there is exactly one valid result.
--- A 'Left' value indicates a parse error.
---
--- /Since: 4.6.0.0/
-readEither :: Read a => String -> Either String a
-readEither s =
-  case [ x | (x,"") <- readPrec_to_S read' minPrec s ] of
-    [x] -> Right x
-    []  -> Left "Prelude.read: no parse"
-    _   -> Left "Prelude.read: ambiguous parse"
- where
-  read' =
-    do x <- readPrec
-       lift P.skipSpaces
-       return x
-
--- | Parse a string using the 'Read' instance.
--- Succeeds if there is exactly one valid result.
---
--- /Since: 4.6.0.0/
-readMaybe :: Read a => String -> Maybe a
-readMaybe s = case readEither s of
-                Left _  -> Nothing
-                Right a -> Just a
-#endif
diff --git a/src/Text/Read/Compat/Repl.hs b/src/Text/Read/Compat/Repl.hs
--- a/src/Text/Read/Compat/Repl.hs
+++ b/src/Text/Read/Compat/Repl.hs
@@ -1,5 +1,5 @@
 {-# LANGUAGE PackageImports #-}
-{-# OPTIONS_GHC -fno-warn-dodgy-exports -fno-warn-unused-imports #-}
+{-# OPTIONS_GHC -Wno-dodgy-exports -Wno-unused-imports #-}
 -- | Reexports "Text.Read.Compat"
 -- from a globally unique namespace.
 module Text.Read.Compat.Repl (
diff --git a/src/Text/Read/Lex/Compat.hs b/src/Text/Read/Lex/Compat.hs
new file mode 100644
--- /dev/null
+++ b/src/Text/Read/Lex/Compat.hs
@@ -0,0 +1,32 @@
+{-# LANGUAGE CPP, NoImplicitPrelude #-}
+{-# LANGUAGE Trustworthy #-}
+module Text.Read.Lex.Compat (
+  module Base
+, readBinP
+) where
+
+import Text.Read.Lex as Base
+
+#if !(MIN_VERSION_base(4,16,0))
+import Data.Char (ord)
+import Prelude
+import Text.ParserCombinators.ReadP (ReadP)
+#endif
+
+#if !(MIN_VERSION_base(4,16,0))
+readBinP :: (Eq a, Num a) => ReadP a
+readBinP = readIntP'2
+{-# SPECIALISE readBinP :: ReadP Integer #-}
+
+readIntP'2 :: (Eq a, Num a) => ReadP a
+readIntP'2 = readIntP 2 isDigit valDigit
+ where
+  isDigit  c = maybe False (const True) (valDig2 c)
+  valDigit c = maybe 0     id           (valDig2 c)
+{-# SPECIALISE readIntP'2 :: ReadP Integer #-}
+
+valDig2 :: Char -> Maybe Int
+valDig2 c
+  | '0' <= c && c <= '1' = Just (ord c - ord '0')
+  | otherwise            = Nothing
+#endif
diff --git a/src/Text/Read/Lex/Compat/Repl.hs b/src/Text/Read/Lex/Compat/Repl.hs
new file mode 100644
--- /dev/null
+++ b/src/Text/Read/Lex/Compat/Repl.hs
@@ -0,0 +1,8 @@
+{-# LANGUAGE PackageImports #-}
+{-# OPTIONS_GHC -Wno-dodgy-exports -Wno-unused-imports #-}
+-- | Reexports "Text.Read.Lex.Compat"
+-- from a globally unique namespace.
+module Text.Read.Lex.Compat.Repl (
+  module Text.Read.Lex.Compat
+) where
+import "this" Text.Read.Lex.Compat
diff --git a/src/Type/Reflection/Compat.hs b/src/Type/Reflection/Compat.hs
--- a/src/Type/Reflection/Compat.hs
+++ b/src/Type/Reflection/Compat.hs
@@ -1,16 +1,23 @@
 {-# LANGUAGE CPP, NoImplicitPrelude #-}
-#if __GLASGOW_HASKELL__ >= 702
 {-# LANGUAGE Trustworthy #-}
-#endif
-#if MIN_VERSION_base(4,10,0) && !(MIN_VERSION_base(4,11,0))
+#if MIN_VERSION_base(4,10,0)
+{-# LANGUAGE GADTs #-}
+{-# LANGUAGE PatternSynonyms #-}
+{-# LANGUAGE PolyKinds #-}
 {-# LANGUAGE RankNTypes #-}
 {-# LANGUAGE ScopedTypeVariables #-}
+{-# LANGUAGE TypeOperators #-}
+{-# LANGUAGE ViewPatterns #-}
+# if !(MIN_VERSION_base(4,11,0))
 {-# LANGUAGE TypeInType #-}
+# endif
 #endif
 module Type.Reflection.Compat (
 #if MIN_VERSION_base(4,10,0)
   module Base
 , withTypeable
+, pattern TypeRep
+, decTypeRep
 #endif
 ) where
 
@@ -20,11 +27,20 @@
 import Type.Reflection as Base hiding (withTypeable)
 #endif
 
-#if MIN_VERSION_base(4,10,0) && !(MIN_VERSION_base(4,11,0))
+#if MIN_VERSION_base(4,10,0)
+# if !(MIN_VERSION_base(4,11,0))
 import GHC.Exts (TYPE)
 import Type.Reflection (Typeable, TypeRep)
+# endif
+
+# if !(MIN_VERSION_base(4,19,0))
+import Data.Void (Void)
+import Prelude.Compat
+import Type.Reflection.Unsafe (typeRepFingerprint)
 import Unsafe.Coerce (unsafeCoerce)
+# endif
 
+# if !(MIN_VERSION_base(4,11,0))
 -- | Use a 'TypeRep' as 'Typeable' evidence.
 withTypeable :: forall (a :: k) (r :: TYPE rep). ()
              => TypeRep a -> (Typeable a => r) -> r
@@ -34,4 +50,57 @@
 
 -- | A helper to satisfy the type checker in 'withTypeable'.
 newtype Gift a (r :: TYPE rep) = Gift (Typeable a => r)
+# endif
+
+# if !(MIN_VERSION_base(4,17,0))
+-- | A 'TypeableInstance' wraps up a 'Typeable' instance for explicit
+-- handling. For internal use: for defining 'TypeRep' pattern.
+data TypeableInstance (a :: k) where
+ TypeableInstance :: Typeable a => TypeableInstance a
+
+-- | Get a reified 'Typeable' instance from an explicit 'TypeRep'.
+--
+-- For internal use: for defining 'TypeRep' pattern.
+typeableInstance :: forall a. TypeRep a -> TypeableInstance a
+typeableInstance rep = withTypeable rep TypeableInstance
+
+-- | A explicitly bidirectional pattern synonym to construct a
+-- concrete representation of a type.
+--
+-- As an __expression__: Constructs a singleton @TypeRep a@ given a
+-- implicit 'Typeable a' constraint:
+--
+-- @
+-- TypeRep @a :: Typeable a => TypeRep a
+-- @
+--
+-- As a __pattern__: Matches on an explicit @TypeRep a@ witness bringing
+-- an implicit @Typeable a@ constraint into scope.
+--
+-- @
+-- f :: TypeRep a -> ..
+-- f TypeRep = {- Typeable a in scope -}
+-- @
+--
+-- /Since: 4.17.0.0/
+pattern TypeRep :: forall a. () => Typeable a => TypeRep a
+pattern TypeRep <- (typeableInstance -> TypeableInstance)
+  where TypeRep = typeRep
+# endif
+
+# if !(MIN_VERSION_base(4,19,0))
+-- | Type equality decision
+--
+-- /Since: 4.19.0.0/
+decTypeRep :: forall k1 k2 (a :: k1) (b :: k2).
+             TypeRep a -> TypeRep b -> Either (a :~~: b -> Void) (a :~~: b)
+decTypeRep a b
+  | sameTypeRep a b = Right (unsafeCoerce HRefl)
+  | otherwise       = Left (\HRefl -> errorWithoutStackTrace ("decTypeRep: Impossible equality proof " ++ show a ++ " :~: " ++ show b))
+{-# INLINEABLE decTypeRep #-}
+
+sameTypeRep :: forall k1 k2 (a :: k1) (b :: k2).
+               TypeRep a -> TypeRep b -> Bool
+sameTypeRep a b = typeRepFingerprint a == typeRepFingerprint b
+# endif
 #endif
diff --git a/src/Type/Reflection/Compat/Repl.hs b/src/Type/Reflection/Compat/Repl.hs
--- a/src/Type/Reflection/Compat/Repl.hs
+++ b/src/Type/Reflection/Compat/Repl.hs
@@ -1,5 +1,5 @@
 {-# LANGUAGE PackageImports #-}
-{-# OPTIONS_GHC -fno-warn-dodgy-exports -fno-warn-unused-imports #-}
+{-# OPTIONS_GHC -Wno-dodgy-exports -Wno-unused-imports #-}
 -- | Reexports "Type.Reflection.Compat"
 -- from a globally unique namespace.
 module Type.Reflection.Compat.Repl (
