diff --git a/benchmarks/bench.hs b/benchmarks/bench.hs
--- a/benchmarks/bench.hs
+++ b/benchmarks/bench.hs
@@ -1,38 +1,36 @@
-import Criterion.Main (defaultMainWith, defaultConfig, bench, bgroup, whnf, Benchmark)
+import Criterion.Main (Benchmark, bench, bgroup, defaultConfig, defaultMainWith, whnf)
 import Criterion.Types (Config (reportFile))
-
-import qualified Invert as I
+import Invert qualified as I
+import Prelude
 
 sizes :: [Integer]
 sizes = [100, 500, 2_000, 5_000] :: [Integer]
 
 invertGroup :: String -> I.Strategy Integer Integer -> Benchmark
 invertGroup name strategy =
-    bgroup name $
-        fmap (invertBench strategy) sizes
+  bgroup name $
+    fmap (invertBench strategy) sizes
 
 invertBench :: (Show b, Enum b, Num b) => I.Strategy b b -> b -> Benchmark
 invertBench strategy size =
-    bench (show size) $
-        let
-            f = I.function strategy [1 .. size] (* (2 ^ (10 :: Integer)))
-            f' x = sum (foldMap (\e -> f (x ^ (e :: Integer))) [0 .. 10])
-        in
-            whnf f' size
+  bench (show size) $
+    let f = I.function strategy [1 .. size] (* (2 ^ (10 :: Integer)))
+        f' x = sum (foldMap (\e -> f (x ^ (e :: Integer))) [0 .. 10])
+     in whnf f' size
 
 groups :: [Benchmark]
 groups =
-    [ invertGroup "linearSearchLazy" I.linearSearchLazy
-    , invertGroup "linearSearchStrict" I.linearSearchStrict
-    , invertGroup "binarySearch" I.binarySearch
-    , invertGroup "hashTable" I.hashTable
-    ]
+  [ invertGroup "linearSearchLazy" I.linearSearchLazy,
+    invertGroup "linearSearchStrict" I.linearSearchStrict,
+    invertGroup "binarySearch" I.binarySearch,
+    invertGroup "hashTable" I.hashTable
+  ]
 
 config :: Config
 config =
-    defaultConfig
-        { reportFile = Just "bench.html"
-        }
+  defaultConfig
+    { reportFile = Just "bench.html"
+    }
 
 main :: IO ()
 main = defaultMainWith config groups
diff --git a/changelog.md b/changelog.md
--- a/changelog.md
+++ b/changelog.md
@@ -1,3 +1,7 @@
+### 1.0.0.4 (2023-06-26)
+
+Raise language to GHC2021
+
 ### 1.0.0.3 (2023-01-11)
 
 Packaging and documentation improvement
diff --git a/examples/billing-codes.hs b/examples/billing-codes.hs
--- a/examples/billing-codes.hs
+++ b/examples/billing-codes.hs
@@ -1,45 +1,33 @@
-{-# LANGUAGE DeriveGeneric #-}
-    -- Enables stock deriving of the Generic class
-
-{-# LANGUAGE DeriveAnyClass #-}
-    -- Enables deriving the GEnum class
-
-{-# LANGUAGE DerivingStrategies #-}
-    -- Lets us explicitly say how we want to derive;
-    -- e.g. "deriving stock" or "deriving anyclass"
-
 import Invert
-
+import Prelude
 import System.Exit (die)
 
 data Product = Basic | Standard | Pro
-    deriving stock (Generic, Show, Eq)
-    deriving anyclass GEnum
+  deriving stock (Generic, Show, Eq)
+  deriving anyclass (GEnum)
 
 data Frequency = Monthly | Annual
-    deriving stock (Generic, Show, Eq)
-    deriving anyclass GEnum
+  deriving stock (Generic, Show, Eq)
+  deriving anyclass (GEnum)
 
 data Bill = Bill Product Frequency
-    deriving stock (Generic, Show, Eq)
-    deriving anyclass GEnum
+  deriving stock (Generic, Show, Eq)
+  deriving anyclass (GEnum)
 
 encodeProduct :: Product -> String
 encodeProduct x = case x of
-
-    Basic    -> "p1"
-    Standard -> "p2"
-    Pro      -> "p3"
+  Basic -> "p1"
+  Standard -> "p2"
+  Pro -> "p3"
 
 encodeBill :: Bill -> Integer
 encodeBill x = case x of
-
-    Bill Basic    Monthly -> 10
-    Bill Basic    Annual  -> 11
-    Bill Standard Monthly -> 20
-    Bill Standard Annual  -> 21
-    Bill Pro      Monthly -> 30
-    Bill Pro      Annual  -> 31
+  Bill Basic Monthly -> 10
+  Bill Basic Annual -> 11
+  Bill Standard Monthly -> 20
+  Bill Standard Annual -> 21
+  Bill Pro Monthly -> 30
+  Bill Pro Annual -> 31
 
 decodeProduct :: String -> Maybe Product
 decodeProduct = Invert.injection hashTable genum encodeProduct
@@ -49,20 +37,19 @@
 
 main :: IO ()
 main = do
-
-    encodeProduct Basic    === "p1"
-    encodeProduct Standard === "p2"
+  encodeProduct Basic === "p1"
+  encodeProduct Standard === "p2"
 
-    decodeProduct "p1"     === Just Basic
-    decodeProduct "xyz"    === Nothing
+  decodeProduct "p1" === Just Basic
+  decodeProduct "xyz" === Nothing
 
-    encodeBill (Bill Basic Annual) === 11
-    encodeBill (Bill Pro Monthly)  === 30
+  encodeBill (Bill Basic Annual) === 11
+  encodeBill (Bill Pro Monthly) === 30
 
-    decodeBill 31 === Just (Bill Pro Annual)
-    decodeBill 50 === Nothing
+  decodeBill 31 === Just (Bill Pro Annual)
+  decodeBill 50 === Nothing
 
 (===) :: (Eq a, Show a) => a -> a -> IO ()
-
-a === b | a == b     =  pure ()
-        | otherwise  =  die (show a <> " /= " <> show b)
+a === b
+  | a == b = pure ()
+  | otherwise = die (show a <> " /= " <> show b)
diff --git a/invert.cabal b/invert.cabal
--- a/invert.cabal
+++ b/invert.cabal
@@ -1,7 +1,7 @@
 cabal-version: 3.0
 
 name: invert
-version: 1.0.0.3
+version: 1.0.0.4
 synopsis: Automatically generate a function’s inverse
 category: Functions
 
@@ -23,14 +23,20 @@
 extra-source-files: *.md
 
 common base
-    default-language: Haskell2010
+    default-language: GHC2021
     ghc-options: -Wall
+    default-extensions:
+        DeriveAnyClass
+        DerivingStrategies
+        ExistentialQuantification
+        NamedFieldPuns
+        NoImplicitPrelude
     build-depends:
-      , base ^>= 4.14 || ^>= 4.15 || ^>= 4.16 || ^>= 4.17
-      , containers ^>= 0.6.4
-      , hashable ^>= 1.3.5 || ^>= 1.4
-      , unordered-containers ^>= 0.2.17
-      , generic-deriving ^>= 1.14.1
+      , base ^>= 4.16 || ^>= 4.17 || ^>= 4.18
+      , containers ^>= 0.6.5
+      , hashable ^>= 1.4.2
+      , unordered-containers ^>= 0.2.19
+      , generic-deriving ^>= 1.14.4
       , vector ^>= 0.12.3 || ^>= 0.13
 
 library
@@ -42,10 +48,6 @@
         Map
         Vector
     hs-source-dirs: src
-    default-extensions:
-        NoImplicitPrelude
-        NamedFieldPuns
-        ExistentialQuantification
 
 test-suite billing-codes-example
     import: base
@@ -57,7 +59,6 @@
 
 benchmark invert-benchmark
     import: base
-    default-extensions: NumericUnderscores
     type: exitcode-stdio-1.0
     hs-source-dirs: benchmarks
     main-is: bench.hs
diff --git a/src/Invert.hs b/src/Invert.hs
--- a/src/Invert.hs
+++ b/src/Invert.hs
@@ -1,203 +1,217 @@
-{-# language Safe #-}
+{-# LANGUAGE Safe #-}
 
 module Invert
-  (
-    {- * Overview -} {- $overview -}
+  ( -- * Overview
+    -- $overview
 
-    {- * 1. Varieties of function -}
-            function, bijection, injection, surjection,
+    -- * 1. Varieties of function
+    function,
+    bijection,
+    injection,
+    surjection,
 
-    {- * 2. Inversion strategies -} linearSearchLazy,
-            linearSearchStrict, binarySearch, hashTable,
+    -- * 2. Inversion strategies
+    linearSearchLazy,
+    linearSearchStrict,
+    binarySearch,
+    hashTable,
 
-    {- * 3. Domain enumeration -} enumBounded, genum,
+    -- * 3. Domain enumeration
+    enumBounded,
+    genum,
 
-    {- * The Strategy type -} Strategy, {- $strategyCreation -}
-            strategyAll, strategyOneAndAll,
+    -- * The Strategy type
+    Strategy,
+    -- $strategyCreation
+    strategyAll,
+    strategyOneAndAll,
 
-    {- * Re-exports -} {- $reexports -} module Invert.Reexport,
+    -- * Re-exports
+    -- $reexports
+    module Invert.Reexport,
   )
-  where
-
-import Invert.Reexport
-
-import qualified Map
-import Map (Map (Map))
-
-import qualified Vector
+where
 
 import Data.Eq (Eq, (==))
 import Data.Foldable (foldl')
 import Data.Function ((.))
+import Data.List qualified as List (lookup, map)
 import Data.List.NonEmpty (NonEmpty, nonEmpty)
 import Data.Maybe (Maybe (Just, Nothing), fromMaybe, listToMaybe)
+import Data.Maybe qualified as List (mapMaybe)
 import Data.Ord (Ord)
 import Data.Tuple (uncurry)
-import Prelude (error)
-import Prelude (Enum, enumFromTo)
-import Prelude (Bounded, minBound, maxBound)
-
-import qualified Data.List as List (lookup, map)
-import qualified Data.Maybe as List (mapMaybe)
-import qualified Generics.Deriving as GEnum (genum)
-
-{- $overview
-
-There are three considerations when you’re inverting a function:
-
-  1. Is it an injection, a surjection, both (a bijection), or neither?
-  2. What data structure do you want to use for efficient lookups?
-  3. Can you produce a list of all values in the function’s domain?
-
-=== 1. What sort of function do you have?
-
-This question determines the type of the function’s inverse.
-
-For a function @(a -> b)@, we call @(a)@ its /domain/, and @(b)@ its /codomain/.
-
-  * In general, when you invert a 'function' of type @(a -> b)@,
-    the type of the inverse is @(b -> [a])@.
-    The result is a list because it contains all domain values that
-    map to a given codomain value; there may be none, one, or many.
-
-  * If your function @(a -> b)@ is a 'bijection',
-    you can invert it to get a function @(b -> a)@.
-    Bijections are quite pleasing in this way.
-
-  * If no two domain values map to the same codomain value,
-    then your function is an 'injection',
-    and it has an inverse of type @(b -> 'Maybe' a)@.
-
-  * If every codomain value has some domain value that maps to it,
-    then your function is a 'surjection',
-    and it has an inverse of type @(b -> 'NonEmpty' a)@.
-
-You are responsible for determining which is appropriate for a particular
-situation: 'function', 'bijection', 'injection', or 'surjection'.
-Choose carefully; the wrong choice may produce an inverse which is
-partial or incorrect.
-
-=== 2. How can we produce a reasonably efficient inversion?
-
-The simplest inversion strategies, 'linearSearchLazy' and 'linearSearchStrict',
-apply the function to each element of the domain, one by one.
-We call this a /linear search/ because the time required for each
-application has a linear correspondence with the size of the domain.
-
-  * 'linearSearchStrict' works by precomputing a strict sequence
-    of tuples, one for each value of the domain.
-
-  * 'linearSearchLazy' precomputes nothing at all.
-    It is possible to use this strategy when the domain is infinite.
-
-Our other two strategies, 'binarySearch' and 'hashTable',
-work by building data structures that allow more efficient lookups.
-
-  * 'binarySearch' precomputes a binary search tree;
-    the codomain must belong to the 'Ord' class.
-
-  * 'hashTable' precomputes a hash table;
-    the codomain must belong to the 'Hashable' class.
-
-The 'Hashable' class comes from "Data.Hashable" in the @hashable@ package.
-The class is re-exported by "Invert", which you may find convenient if
-your primary motivation for deriving 'Hashable' is to invert a function.
-
-=== 3. How will you enumerate the domain?
-
-Inverting a function @(a -> b)@ requires having a list of all
-possible values of domain @(a)@; from this, we can apply the
-function to every value to produce a list of tuples that
-completely describes the function.
-
-We offer two suggestions for automatically producing this list:
-
-  * 'enumBounded' uses two stock-derivable classes, 'Enum' and 'Bounded'.
-  * 'genum' uses GHC generics; it requires deriving 'Generic' and 'GEnum'.
+import Generics.Deriving qualified as GEnum (genum)
+import Invert.Reexport
+import Map (Map (Map))
+import Map qualified
+import Vector qualified
+import Prelude (Bounded, Enum, enumFromTo, error, maxBound, minBound)
 
-The 'Generic' class comes from "GHC.Generics", and the 'GEnum' class
-comes from "Generics.Deriving" in the @generic-deriving@ package.
-Both classes are re-exported by "Invert", which you may find convenient
-if your primary motivation for deriving 'GEnum' is to invert a function. -}
+-- $overview
+--
+-- There are three considerations when you’re inverting a function:
+--
+--   1. Is it an injection, a surjection, both (a bijection), or neither?
+--   2. What data structure do you want to use for efficient lookups?
+--   3. Can you produce a list of all values in the function’s domain?
+--
+-- === 1. What sort of function do you have?
+--
+-- This question determines the type of the function’s inverse.
+--
+-- For a function @(a -> b)@, we call @(a)@ its /domain/, and @(b)@ its /codomain/.
+--
+--   * In general, when you invert a 'function' of type @(a -> b)@,
+--     the type of the inverse is @(b -> [a])@.
+--     The result is a list because it contains all domain values that
+--     map to a given codomain value; there may be none, one, or many.
+--
+--   * If your function @(a -> b)@ is a 'bijection',
+--     you can invert it to get a function @(b -> a)@.
+--     Bijections are quite pleasing in this way.
+--
+--   * If no two domain values map to the same codomain value,
+--     then your function is an 'injection',
+--     and it has an inverse of type @(b -> 'Maybe' a)@.
+--
+--   * If every codomain value has some domain value that maps to it,
+--     then your function is a 'surjection',
+--     and it has an inverse of type @(b -> 'NonEmpty' a)@.
+--
+-- You are responsible for determining which is appropriate for a particular
+-- situation: 'function', 'bijection', 'injection', or 'surjection'.
+-- Choose carefully; the wrong choice may produce an inverse which is
+-- partial or incorrect.
+--
+-- === 2. How can we produce a reasonably efficient inversion?
+--
+-- The simplest inversion strategies, 'linearSearchLazy' and 'linearSearchStrict',
+-- apply the function to each element of the domain, one by one.
+-- We call this a /linear search/ because the time required for each
+-- application has a linear correspondence with the size of the domain.
+--
+--   * 'linearSearchStrict' works by precomputing a strict sequence
+--     of tuples, one for each value of the domain.
+--
+--   * 'linearSearchLazy' precomputes nothing at all.
+--     It is possible to use this strategy when the domain is infinite.
+--
+-- Our other two strategies, 'binarySearch' and 'hashTable',
+-- work by building data structures that allow more efficient lookups.
+--
+--   * 'binarySearch' precomputes a binary search tree;
+--     the codomain must belong to the 'Ord' class.
+--
+--   * 'hashTable' precomputes a hash table;
+--     the codomain must belong to the 'Hashable' class.
+--
+-- The 'Hashable' class comes from "Data.Hashable" in the @hashable@ package.
+-- The class is re-exported by "Invert", which you may find convenient if
+-- your primary motivation for deriving 'Hashable' is to invert a function.
+--
+-- === 3. How will you enumerate the domain?
+--
+-- Inverting a function @(a -> b)@ requires having a list of all
+-- possible values of domain @(a)@; from this, we can apply the
+-- function to every value to produce a list of tuples that
+-- completely describes the function.
+--
+-- We offer two suggestions for automatically producing this list:
+--
+--   * 'enumBounded' uses two stock-derivable classes, 'Enum' and 'Bounded'.
+--   * 'genum' uses GHC generics; it requires deriving 'Generic' and 'GEnum'.
+--
+-- The 'Generic' class comes from "GHC.Generics", and the 'GEnum' class
+-- comes from "Generics.Deriving" in the @generic-deriving@ package.
+-- Both classes are re-exported by "Invert", which you may find convenient
+-- if your primary motivation for deriving 'GEnum' is to invert a function.
 
 function ::
-    Strategy a b
-    -> [a]        -- ^ A complete list of all the values of the domain.
-    -> (a -> b)   -- ^ The function to invert.
-    -> (b -> [a]) -- ^ The inverse of the given function.
-
+  Strategy a b ->
+  -- | A complete list of all the values of the domain.
+  [a] ->
+  -- | The function to invert.
+  (a -> b) ->
+  -- | The inverse of the given function.
+  (b -> [a])
 bijection ::
-    Strategy a b
-    -> [a]
-                -- ^ A complete list of all the values of the domain.
-    -> (a -> b)
-                -- ^ The function to invert.
-                --   __This function must be bijective!__
-                --   This means that every value in the codomain has
-                --   exactly one value in the domain that maps to it.
-    -> (b -> a)
-                -- ^ The inverse of the given function.
-
+  Strategy a b ->
+  -- | A complete list of all the values of the domain.
+  [a] ->
+  -- | The function to invert.
+  --   __This function must be bijective!__
+  --   This means that every value in the codomain has
+  --   exactly one value in the domain that maps to it.
+  (a -> b) ->
+  -- | The inverse of the given function.
+  (b -> a)
 injection ::
-    Strategy a b
-    -> [a]
-                -- ^ A complete list of all the values of the domain.
-    -> (a -> b)
-                -- ^ The function to invert.
-                --   __This function must be injective!__
-                --   This means that no two values in the domain map
-                --   to the same value of the codomain.
-    -> (b -> Maybe a)
-                -- ^ The inverse of the given function.
-
+  Strategy a b ->
+  -- | A complete list of all the values of the domain.
+  [a] ->
+  -- | The function to invert.
+  --   __This function must be injective!__
+  --   This means that no two values in the domain map
+  --   to the same value of the codomain.
+  (a -> b) ->
+  -- | The inverse of the given function.
+  (b -> Maybe a)
 surjection ::
-    Strategy a b
-    -> [a]
-                -- ^ A complete list of all the values of the domain.
-    -> (a -> b)
-                -- ^ The function to invert.
-                --   __This function must be surjective!__
-                --   This means that every value in the codomain has
-                --   at least one value in the domain that maps to it.
-    -> (b -> NonEmpty a)
-                -- ^ The inverse of the given function.
-
+  Strategy a b ->
+  -- | A complete list of all the values of the domain.
+  [a] ->
+  -- | The function to invert.
+  --   __This function must be surjective!__
+  --   This means that every value in the codomain has
+  --   at least one value in the domain that maps to it.
+  (a -> b) ->
+  -- | The inverse of the given function.
+  (b -> NonEmpty a)
 function (Strategy _ s) as f = s (inverseEntries as f)
-injection (Strategy s _) as f = s (inverseEntries as f)
-bijection (Strategy s _) as f = finagle . s (inverseEntries as f)
-  where finagle = fromMaybe (error "Not a bijection!")
-surjection (Strategy _ s) as f = finagle . s (inverseEntries as f)
-  where finagle = fromMaybe (error "Not a surjection!") . nonEmpty
 
-{-| An inversion strategy is an approach for producing
-    the inverse of an @(a -> b)@ function
+injection (Strategy s _) as f = s (inverseEntries as f)
 
-All strategies produce the same results, but they
-have operational differences that affect performance. -}
-data Strategy a b =
-  Strategy
-    ([(b, a)] -> b -> Maybe a)
-    ([(b, a)] -> b -> [a])
+bijection (Strategy s _) as f = finagle . s (inverseEntries as f)
+  where
+    finagle = fromMaybe (error "Not a bijection!")
 
-{- $strategyCreation
+surjection (Strategy _ s) as f = finagle . s (inverseEntries as f)
+  where
+    finagle = fromMaybe (error "Not a surjection!") . nonEmpty
 
-=== Defining your own strategies
+-- | An inversion strategy is an approach for producing
+--    the inverse of an @(a -> b)@ function
+--
+-- All strategies produce the same results, but they
+-- have operational differences that affect performance.
+data Strategy a b
+  = Strategy
+      ([(b, a)] -> b -> Maybe a)
+      ([(b, a)] -> b -> [a])
 
-If you want to design your own strategy instead
-of using one provided by this module, use either
-'strategyAll' or 'strategyOneAndAll'. -}
+-- $strategyCreation
+--
+-- === Defining your own strategies
+--
+-- If you want to design your own strategy instead
+-- of using one provided by this module, use either
+-- 'strategyAll' or 'strategyOneAndAll'.
 
 strategyAll ::
-    ([(b, a)] -> b -> [a]) -- ^ Find all matches
-    -> Strategy a b
+  -- | Find all matches
+  ([(b, a)] -> b -> [a]) ->
+  Strategy a b
 strategyAll all = strategyOneAndAll one all
   where
     one bas b = listToMaybe (all bas b)
 
 strategyOneAndAll ::
-    ([(b, a)] -> b -> Maybe a) -- ^ Find the first match
-    -> ([(b, a)] -> b -> [a]) -- ^ Find all matches
-    -> Strategy a b
+  -- | Find the first match
+  ([(b, a)] -> b -> Maybe a) ->
+  -- | Find all matches
+  ([(b, a)] -> b -> [a]) ->
+  Strategy a b
 strategyOneAndAll = Strategy
 
 inverseEntries :: [a] -> (a -> b) -> [(b, a)]
@@ -206,23 +220,23 @@
 mapStrategy :: Map Maybe b a -> Map [] b a -> Strategy a b
 mapStrategy one all = Strategy (f one) (f all)
   where
-    f Map{ Map.empty, Map.singleton, Map.union, Map.lookup } =
-        lookup . foldl' union empty . List.map (uncurry singleton)
-
-{-| A function inversion strategy that precomputes nothing at all
+    f Map {Map.empty, Map.singleton, Map.union, Map.lookup} =
+      lookup . foldl' union empty . List.map (uncurry singleton)
 
-It is possible to use this strategy when the domain is infinite. -}
+-- | A function inversion strategy that precomputes nothing at all
+--
+-- It is possible to use this strategy when the domain is infinite.
 linearSearchLazy :: Eq b => Strategy a b
 linearSearchLazy = Strategy one all
   where
     one bas b = List.lookup b bas
     all bas b = List.mapMaybe (sndIfFstEq b) bas
 
-{-| A function inversion strategy that works by precomputing a
-    strict sequence of tuples, one for each value of the domain
-
-For larger functions, it may be preferable to use 'binarySearch' or
-'hashTable' instead to get a more efficient inverse. -}
+-- | A function inversion strategy that works by precomputing a
+--    strict sequence of tuples, one for each value of the domain
+--
+-- For larger functions, it may be preferable to use 'binarySearch' or
+-- 'hashTable' instead to get a more efficient inverse.
 linearSearchStrict :: Eq b => Strategy a b
 linearSearchStrict = strategyAll f
   where
@@ -233,64 +247,64 @@
 sndIfFstEq :: Eq b => b -> (b, a) -> Maybe a
 sndIfFstEq x (b, a) = if b == x then Just a else Nothing
 
-{-| A function inversion strategy that works by precomputing
-    a binary search tree
-
-The data structure imposes the requirement that the codomain
-belongs to the 'Ord' class. -}
+-- | A function inversion strategy that works by precomputing
+--    a binary search tree
+--
+-- The data structure imposes the requirement that the codomain
+-- belongs to the 'Ord' class.
 binarySearch :: Ord b => Strategy a b
 binarySearch = mapStrategy Map.ordSingleMap Map.ordMultiMap
 
-{-| A function inversion strategy that works by precomputing
-    a hash table
-
-The data structure imposes the requirement that the codomain
-belongs to the 'Hashable' class. -}
+-- | A function inversion strategy that works by precomputing
+--    a hash table
+--
+-- The data structure imposes the requirement that the codomain
+-- belongs to the 'Hashable' class.
 hashTable :: (Eq b, Hashable b) => Strategy a b
 hashTable = mapStrategy Map.hashSingleMap Map.hashMultiMap
 
-{-| A convenient way to enumerate the domain for a function that you
-want to invert, using the stock-derivable classes 'Enum' and 'Bounded'
-
-To derive the required typeclass instances, add the following deriving clause to
-the type’s definition:
-
-@
-deriving (Enum, Bounded)
-@ -}
+-- | A convenient way to enumerate the domain for a function that you
+-- want to invert, using the stock-derivable classes 'Enum' and 'Bounded'
+--
+-- To derive the required typeclass instances, add the following deriving clause to
+-- the type’s definition:
+--
+-- @
+-- deriving (Enum, Bounded)
+-- @
 enumBounded :: (Enum a, Bounded a) => [a]
 enumBounded = enumFromTo minBound maxBound
 
-{-| Use GHC generics to enumerate a function's domain
-
-This requires deriving 'Generic' and 'GEnum'. The 'Generic' class comes
-from "GHC.Generics", and the 'GEnum' class comes from "Generics.Deriving"
-in the @generic-deriving@ package.
-
-To derive the required typeclass instances, enable the following
-language extensions:
-
-@
-\{\-# language DeriveGeneric, DeriveAnyClass, DerivingStrategies #\-\}
-@
-
-Then add the following deriving clauses to the type’s definition:
-
-@
-deriving stock Generic
-deriving anyclass GEnum
-@ -}
+-- | Use GHC generics to enumerate a function's domain
+--
+-- This requires deriving 'Generic' and 'GEnum'. The 'Generic' class comes
+-- from "GHC.Generics", and the 'GEnum' class comes from "Generics.Deriving"
+-- in the @generic-deriving@ package.
+--
+-- To derive the required typeclass instances, enable the following
+-- language extensions:
+--
+-- @
+-- \{\-# language DeriveGeneric, DeriveAnyClass, DerivingStrategies #\-\}
+-- @
+--
+-- Then add the following deriving clauses to the type’s definition:
+--
+-- @
+-- deriving stock Generic
+-- deriving anyclass GEnum
+-- @
 genum :: GEnum a => [a]
 genum = GEnum.genum
 
-{- $reexports
-
-This module provides a few definitions that come directly from
-other packages. These are here to let you conveniently derive
-'Hashable' and 'GEnum' with only the "Invert" module imported.
-
-List of re-exports:
-
-  - __'Hashable'__ (for the 'hashTable' inversion strategy)
-  - __'Generic'__ and __'GEnum'__ (for the 'genum' domain
-    enumeration approach) -}
+-- $reexports
+--
+-- This module provides a few definitions that come directly from
+-- other packages. These are here to let you conveniently derive
+-- 'Hashable' and 'GEnum' with only the "Invert" module imported.
+--
+-- List of re-exports:
+--
+--   - __'Hashable'__ (for the 'hashTable' inversion strategy)
+--   - __'Generic'__ and __'GEnum'__ (for the 'genum' domain
+--     enumeration approach)
diff --git a/src/Invert/Reexport.hs b/src/Invert/Reexport.hs
--- a/src/Invert/Reexport.hs
+++ b/src/Invert/Reexport.hs
@@ -1,12 +1,17 @@
-{-# language Safe #-}
+{-# LANGUAGE Safe #-}
 
 module Invert.Reexport
-  (
-    {- * Hashable -} Hashable,
-    {- * Generic  -} Generic,
-    {- * GEnum    -} GEnum
-  ) where
+  ( -- * Hashable
+    Hashable,
 
-import Data.Hashable     ( Hashable )
-import Generics.Deriving ( GEnum )
-import GHC.Generics      ( Generic )
+    -- * Generic
+    Generic,
+
+    -- * GEnum
+    GEnum,
+  )
+where
+
+import Data.Hashable (Hashable)
+import GHC.Generics (Generic)
+import Generics.Deriving (GEnum)
diff --git a/src/Map.hs b/src/Map.hs
--- a/src/Map.hs
+++ b/src/Map.hs
@@ -1,38 +1,47 @@
-{-# language Safe #-}
+{-# LANGUAGE Safe #-}
 
 module Map where
 
-import Data.Eq       ( Eq )
-import Data.Hashable ( Hashable )
-import Data.Maybe    ( Maybe, maybe )
-import Data.Ord      ( Ord )
-
-import qualified Data.Foldable
-    as Seq (toList)
-
-import qualified Data.HashMap.Strict
-    as HashMap (lookup, singleton, empty, union, unionWith)
-
-import qualified Data.Map.Strict
-    as OrdMap (lookup, singleton, empty, union, unionWith)
-
-import qualified Data.Sequence
-    as Seq (singleton, (><))
+import Data.Eq (Eq)
+import Data.Foldable qualified as Seq
+  ( toList,
+  )
+import Data.HashMap.Strict qualified as HashMap
+  ( empty,
+    lookup,
+    singleton,
+    union,
+    unionWith,
+  )
+import Data.Hashable (Hashable)
+import Data.Map.Strict qualified as OrdMap
+  ( empty,
+    lookup,
+    singleton,
+    union,
+    unionWith,
+  )
+import Data.Maybe (Maybe, maybe)
+import Data.Ord (Ord)
+import Data.Sequence qualified as Seq
+  ( singleton,
+    (><),
+  )
 
 data Map f a b = forall map.
   Map
-    { empty :: map
-    , singleton :: a -> b -> map
-    , union :: map -> map -> map
-    , lookup :: map -> a -> f b
-    }
+  { empty :: map,
+    singleton :: a -> b -> map,
+    union :: map -> map -> map,
+    lookup :: map -> a -> f b
+  }
 
 type SingleMap = Map Maybe
 
 type MultiMap = Map []
 
 hashSingleMap :: (Eq a, Hashable a) => SingleMap a b
-hashSingleMap = Map{ empty, singleton, union, lookup }
+hashSingleMap = Map {empty, singleton, union, lookup}
   where
     empty = HashMap.empty
     singleton = HashMap.singleton
@@ -40,7 +49,7 @@
     lookup m a = HashMap.lookup a m
 
 hashMultiMap :: (Eq a, Hashable a) => MultiMap a b
-hashMultiMap = Map{ empty, singleton, union, lookup }
+hashMultiMap = Map {empty, singleton, union, lookup}
   where
     empty = HashMap.empty
     singleton = \a b -> HashMap.singleton a (Seq.singleton b)
@@ -48,7 +57,7 @@
     lookup = \m a -> maybe [] Seq.toList (HashMap.lookup a m)
 
 ordSingleMap :: Ord a => SingleMap a b
-ordSingleMap = Map{ empty, singleton, union, lookup }
+ordSingleMap = Map {empty, singleton, union, lookup}
   where
     empty = OrdMap.empty
     singleton = OrdMap.singleton
@@ -56,7 +65,7 @@
     lookup m a = OrdMap.lookup a m
 
 ordMultiMap :: Ord a => MultiMap a b
-ordMultiMap = Map{ empty, singleton, union, lookup }
+ordMultiMap = Map {empty, singleton, union, lookup}
   where
     empty = OrdMap.empty
     singleton = \a b -> OrdMap.singleton a (Seq.singleton b)
diff --git a/src/Vector.hs b/src/Vector.hs
--- a/src/Vector.hs
+++ b/src/Vector.hs
@@ -1,11 +1,10 @@
-{-# language Trustworthy #-}
+{-# LANGUAGE Trustworthy #-}
 
 module Vector (fromList, toList, mapMaybe) where
 
 import Data.Maybe (Maybe)
-
 import Data.Vector (Vector)
-import qualified Data.Vector as V
+import Data.Vector qualified as V
 
 fromList :: [a] -> Vector a
 fromList = V.fromList
