diff --git a/LICENSE.markdown b/LICENSE.markdown
--- a/LICENSE.markdown
+++ b/LICENSE.markdown
@@ -1,6 +1,6 @@
 MIT License
 
-Copyright (c) 2022 Taylor Fausak
+Copyright (c) 2023 Taylor Fausak
 
 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
diff --git a/README.markdown b/README.markdown
--- a/README.markdown
+++ b/README.markdown
@@ -1,6 +1,6 @@
 # Witch
 
-[![CI](https://github.com/tfausak/witch/workflows/Workflow/badge.svg)](https://github.com/tfausak/witch/actions)
+[![Workflow](https://github.com/tfausak/witch/actions/workflows/workflow.yaml/badge.svg)](https://github.com/tfausak/witch/actions/workflows/workflow.yaml)
 [![Hackage](https://img.shields.io/hackage/v/witch)](https://hackage.haskell.org/package/witch)
 [![Stackage](https://www.stackage.org/package/witch/badge/nightly?label=stackage)](https://www.stackage.org/package/witch)
 
diff --git a/source/ghc-8.10/Witch/Lift.hs b/source/ghc-8.10/Witch/Lift.hs
deleted file mode 100644
--- a/source/ghc-8.10/Witch/Lift.hs
+++ /dev/null
@@ -1,48 +0,0 @@
-{-# LANGUAGE ExplicitForAll #-}
-
-module Witch.Lift where
-
-import qualified Data.Typeable as Typeable
-import qualified Language.Haskell.TH.Syntax as TH
-import qualified Witch.TryFrom as TryFrom
-import qualified Witch.Utility as Utility
-
--- | This is like 'Utility.unsafeFrom' except that it works at compile time
--- rather than runtime.
---
--- > -- Avoid this:
--- > unsafeFrom @s "some literal"
--- >
--- > -- Prefer this:
--- > $$(liftedFrom @s "some literal")
-liftedFrom ::
-  forall source target.
-  ( TryFrom.TryFrom source target,
-    TH.Lift target,
-    Show source,
-    Typeable.Typeable source,
-    Typeable.Typeable target
-  ) =>
-  source ->
-  TH.Q (TH.TExp target)
-liftedFrom = TH.liftTyped . Utility.unsafeFrom
-
--- | This is like 'Utility.unsafeInto' except that it works at compile time
--- rather than runtime.
---
--- > -- Avoid this:
--- > unsafeInto @t "some literal"
--- >
--- > -- Prefer this:
--- > $$(liftedInto @t "some literal")
-liftedInto ::
-  forall target source.
-  ( TryFrom.TryFrom source target,
-    TH.Lift target,
-    Show source,
-    Typeable.Typeable source,
-    Typeable.Typeable target
-  ) =>
-  source ->
-  TH.Q (TH.TExp target)
-liftedInto = liftedFrom
diff --git a/source/ghc-8.8/Witch/Lift.hs b/source/ghc-8.8/Witch/Lift.hs
deleted file mode 100644
--- a/source/ghc-8.8/Witch/Lift.hs
+++ /dev/null
@@ -1,48 +0,0 @@
-{-# LANGUAGE ScopedTypeVariables #-}
-
-module Witch.Lift where
-
-import qualified Data.Typeable as Typeable
-import qualified Language.Haskell.TH.Syntax as TH
-import qualified Witch.TryFrom as TryFrom
-import qualified Witch.Utility as Utility
-
--- | This is like 'Utility.unsafeFrom' except that it works at compile time
--- rather than runtime.
---
--- > -- Avoid this:
--- > unsafeFrom @s "some literal"
--- >
--- > -- Prefer this:
--- > $$(liftedFrom @s "some literal")
-liftedFrom ::
-  forall source target.
-  ( TryFrom.TryFrom source target,
-    TH.Lift target,
-    Show source,
-    Typeable.Typeable source,
-    Typeable.Typeable target
-  ) =>
-  source ->
-  TH.Q (TH.TExp target)
-liftedFrom s = TH.unsafeTExpCoerce $ TH.lift (Utility.unsafeFrom s :: target)
-
--- | This is like 'Utility.unsafeInto' except that it works at compile time
--- rather than runtime.
---
--- > -- Avoid this:
--- > unsafeInto @t "some literal"
--- >
--- > -- Prefer this:
--- > $$(liftedInto @t "some literal")
-liftedInto ::
-  forall target source.
-  ( TryFrom.TryFrom source target,
-    TH.Lift target,
-    Show source,
-    Typeable.Typeable source,
-    Typeable.Typeable target
-  ) =>
-  source ->
-  TH.Q (TH.TExp target)
-liftedInto = liftedFrom
diff --git a/source/ghc-9.0/Witch/Lift.hs b/source/ghc-9.0/Witch/Lift.hs
deleted file mode 100644
--- a/source/ghc-9.0/Witch/Lift.hs
+++ /dev/null
@@ -1,50 +0,0 @@
-{-# LANGUAGE ExplicitForAll #-}
-
-module Witch.Lift where
-
-import qualified Data.Typeable as Typeable
-import qualified Language.Haskell.TH.Syntax as TH
-import qualified Witch.TryFrom as TryFrom
-import qualified Witch.Utility as Utility
-
--- | This is like 'Utility.unsafeFrom' except that it works at compile time
--- rather than runtime.
---
--- > -- Avoid this:
--- > unsafeFrom @s "some literal"
--- >
--- > -- Prefer this:
--- > $$(liftedFrom @s "some literal")
-liftedFrom ::
-  forall source target m.
-  ( TryFrom.TryFrom source target,
-    TH.Lift target,
-    Show source,
-    Typeable.Typeable source,
-    Typeable.Typeable target,
-    TH.Quote m
-  ) =>
-  source ->
-  TH.Code m target
-liftedFrom = TH.liftTyped . Utility.unsafeFrom
-
--- | This is like 'Utility.unsafeInto' except that it works at compile time
--- rather than runtime.
---
--- > -- Avoid this:
--- > unsafeInto @t "some literal"
--- >
--- > -- Prefer this:
--- > $$(liftedInto @t "some literal")
-liftedInto ::
-  forall target source m.
-  ( TryFrom.TryFrom source target,
-    TH.Lift target,
-    Show source,
-    Typeable.Typeable source,
-    Typeable.Typeable target,
-    TH.Quote m
-  ) =>
-  source ->
-  TH.Code m target
-liftedInto = liftedFrom
diff --git a/source/library/Witch/From.hs b/source/library/Witch/From.hs
--- a/source/library/Witch/From.hs
+++ b/source/library/Witch/From.hs
@@ -19,7 +19,7 @@
   -- > -- Avoid this:
   -- > from (x :: s)
   -- >
-  -- > -- Prefer this:
+  -- > -- Prefer this (using [@TypeApplications@](https://downloads.haskell.org/~ghc/9.0.1/docs/html/users_guide/exts/type_applications.html) language extension):
   -- > from @s x
   --
   -- The default implementation of this method simply calls 'Coerce.coerce',
@@ -31,5 +31,5 @@
   -- >>> instance From Name String
   -- >>> instance From String Name
   from :: source -> target
-  default from :: Coerce.Coercible source target => source -> target
+  default from :: (Coerce.Coercible source target) => source -> target
   from = Coerce.coerce
diff --git a/source/library/Witch/Instances.hs b/source/library/Witch/Instances.hs
--- a/source/library/Witch/Instances.hs
+++ b/source/library/Witch/Instances.hs
@@ -911,7 +911,7 @@
 -- Ratio
 
 -- | Uses '(Ratio.%)' with a denominator of 1.
-instance Integral a => From.From a (Ratio.Ratio a) where
+instance (Integral a) => From.From a (Ratio.Ratio a) where
   from = (Ratio.% 1)
 
 -- | Uses 'Ratio.numerator' when the denominator is 1.
@@ -930,7 +930,7 @@
   from = fromRational
 
 -- | Uses `fromRational` as long as there isn't a loss of precision.
-instance Fixed.HasResolution a => TryFrom.TryFrom Rational (Fixed.Fixed a) where
+instance (Fixed.HasResolution a) => TryFrom.TryFrom Rational (Fixed.Fixed a) where
   tryFrom = Utility.eitherTryFrom $ \s ->
     let t :: Fixed.Fixed a
         t = fromRational s
@@ -949,13 +949,13 @@
   from (Fixed.MkFixed t) = t
 
 -- | Uses 'toRational'.
-instance Fixed.HasResolution a => From.From (Fixed.Fixed a) Rational where
+instance (Fixed.HasResolution a) => From.From (Fixed.Fixed a) Rational where
   from = toRational
 
 -- Complex
 
 -- | Uses '(Complex.:+)' with an imaginary part of 0.
-instance Num a => From.From a (Complex.Complex a) where
+instance (Num a) => From.From a (Complex.Complex a) where
   from = (Complex.:+ 0)
 
 -- | Uses 'Complex.realPart' when the imaginary part is 0.
@@ -978,7 +978,7 @@
 -- Set
 
 -- | Uses 'Set.fromList'.
-instance Ord a => From.From [a] (Set.Set a) where
+instance (Ord a) => From.From [a] (Set.Set a) where
   from = Set.fromList
 
 -- | Uses 'Set.toAscList'.
@@ -999,7 +999,7 @@
 
 -- | Uses 'Map.fromList'. If there are duplicate keys, later values will
 -- overwrite earlier ones.
-instance Ord k => From.From [(k, v)] (Map.Map k v) where
+instance (Ord k) => From.From [(k, v)] (Map.Map k v) where
   from = Map.fromList
 
 -- | Uses 'Map.toAscList'.
@@ -1539,7 +1539,7 @@
 --
 
 realFloatToRational ::
-  RealFloat s => s -> Either Exception.ArithException Rational
+  (RealFloat s) => s -> Either Exception.ArithException Rational
 realFloatToRational s
   | isNaN s = Left Exception.LossOfPrecision
   | isInfinite s =
@@ -1569,13 +1569,13 @@
 
 -- | The maximum integral value that can be unambiguously represented as a
 -- 'Float'. Equal to 16,777,215.
-maxFloat :: Num a => a
+maxFloat :: (Num a) => a
 maxFloat = 16777215
 
 -- | The maximum integral value that can be unambiguously represented as a
 -- 'Double'. Equal to 9,007,199,254,740,991.
-maxDouble :: Num a => a
+maxDouble :: (Num a) => a
 maxDouble = 9007199254740991
 
-tryEvaluate :: Exception.Exception e => a -> Either e a
+tryEvaluate :: (Exception.Exception e) => a -> Either e a
 tryEvaluate = Unsafe.unsafePerformIO . Exception.try . Exception.evaluate
diff --git a/source/library/Witch/Lift.hs b/source/library/Witch/Lift.hs
new file mode 100644
--- /dev/null
+++ b/source/library/Witch/Lift.hs
@@ -0,0 +1,50 @@
+{-# LANGUAGE ExplicitForAll #-}
+
+module Witch.Lift where
+
+import qualified Data.Typeable as Typeable
+import qualified Language.Haskell.TH.Syntax as TH
+import qualified Witch.TryFrom as TryFrom
+import qualified Witch.Utility as Utility
+
+-- | This is like 'Utility.unsafeFrom' except that it works at compile time
+-- rather than runtime.
+--
+-- > -- Avoid this:
+-- > unsafeFrom @s "some literal"
+-- >
+-- > -- Prefer this:
+-- > $$(liftedFrom @s "some literal")
+liftedFrom ::
+  forall source target m.
+  ( TryFrom.TryFrom source target,
+    TH.Lift target,
+    Show source,
+    Typeable.Typeable source,
+    Typeable.Typeable target,
+    TH.Quote m
+  ) =>
+  source ->
+  TH.Code m target
+liftedFrom = TH.liftTyped . Utility.unsafeFrom
+
+-- | This is like 'Utility.unsafeInto' except that it works at compile time
+-- rather than runtime.
+--
+-- > -- Avoid this:
+-- > unsafeInto @t "some literal"
+-- >
+-- > -- Prefer this:
+-- > $$(liftedInto @t "some literal")
+liftedInto ::
+  forall target source m.
+  ( TryFrom.TryFrom source target,
+    TH.Lift target,
+    Show source,
+    Typeable.Typeable source,
+    Typeable.Typeable target,
+    TH.Quote m
+  ) =>
+  source ->
+  TH.Code m target
+liftedInto = liftedFrom
diff --git a/source/library/Witch/Utility.hs b/source/library/Witch/Utility.hs
--- a/source/library/Witch/Utility.hs
+++ b/source/library/Witch/Utility.hs
@@ -30,7 +30,7 @@
 -- >
 -- > -- Prefer this:
 -- > into @t x
-into :: forall target source. From.From source target => source -> target
+into :: forall target source. (From.From source target) => source -> target
 into = From.from
 
 -- | This function converts from some @source@ type into some @target@ type,
@@ -78,7 +78,7 @@
 -- > tryInto @t x
 tryInto ::
   forall target source.
-  TryFrom.TryFrom source target =>
+  (TryFrom.TryFrom source target) =>
   source ->
   Either (TryFromException.TryFromException source target) target
 tryInto = TryFrom.tryFrom
@@ -136,7 +136,7 @@
 -- > -- Prefer this:
 -- > tryFrom = eitherTryFrom f
 eitherTryFrom ::
-  Exception.Exception exception =>
+  (Exception.Exception exception) =>
   (source -> Either exception target) ->
   source ->
   Either (TryFromException.TryFromException source target) target
diff --git a/source/test-suite/Main.hs b/source/test-suite/Main.hs
--- a/source/test-suite/Main.hs
+++ b/source/test-suite/Main.hs
@@ -2453,32 +2453,32 @@
 anyTryFromException :: Selector (Witch.TryFromException s t)
 anyTryFromException = const True
 
-describe :: Stack.HasCallStack => String -> Spec -> Spec
+describe :: (Stack.HasCallStack) => String -> Spec -> Spec
 describe label = testToSpec . HUnit.TestLabel label . specToTest
 
 hush :: Either x a -> Maybe a
 hush = either (const Nothing) Just
 
-it :: Stack.HasCallStack => String -> HUnit.Assertion -> Spec
+it :: (Stack.HasCallStack) => String -> HUnit.Assertion -> Spec
 it label = testToSpec . HUnit.TestLabel label . HUnit.TestCase
 
 shouldBe :: (Stack.HasCallStack, Eq a, Show a) => a -> a -> HUnit.Assertion
 shouldBe = (HUnit.@?=)
 
 shouldSatisfy :: (Stack.HasCallStack, Show a) => a -> (a -> Bool) -> HUnit.Assertion
-shouldSatisfy value predicate = HUnit.assertBool ("predicate failed on: " ++ show value) $ predicate value
+shouldSatisfy value predicate = HUnit.assertBool ("predicate failed on: " <> show value) $ predicate value
 
 shouldThrow :: (Stack.HasCallStack, Exception.Exception e) => IO a -> Selector e -> HUnit.Assertion
 shouldThrow action predicate = do
   result <- Exception.try action
   case result of
     Right _ -> HUnit.assertFailure "did not get expected exception"
-    Left exception -> HUnit.assertBool ("predicate failed on expected exception: " ++ show exception) $ predicate exception
+    Left exception -> HUnit.assertBool ("predicate failed on expected exception: " <> show exception) $ predicate exception
 
-specToTest :: Stack.HasCallStack => Spec -> HUnit.Test
+specToTest :: (Stack.HasCallStack) => Spec -> HUnit.Test
 specToTest = HUnit.TestList . Foldable.toList . Writer.execWriter
 
-testToSpec :: Stack.HasCallStack => HUnit.Test -> Spec
+testToSpec :: (Stack.HasCallStack) => HUnit.Test -> Spec
 testToSpec = Writer.tell . Seq.singleton
 
 unixEpoch :: Time.UTCTime
diff --git a/witch.cabal b/witch.cabal
--- a/witch.cabal
+++ b/witch.cabal
@@ -1,7 +1,7 @@
 cabal-version: 2.2
 
 name: witch
-version: 1.1.6.0
+version: 1.1.6.1
 synopsis: Convert values from one type into another.
 description: Witch converts values from one type into another.
 
@@ -23,36 +23,27 @@
 
 common library
   build-depends:
-    , base >= 4.10 && < 4.18
-    , bytestring >= 0.10.8 && < 0.12
-    , containers >= 0.5.10 && < 0.7
+    , base >= 4.15 && < 4.18
+    , bytestring >= 0.10.12 && < 0.12
+    , containers >= 0.6.4 && < 0.7
     , tagged >= 0.8.6 && < 0.9
-    , text >= 1.2.3 && < 1.3 || >= 2.0 && < 2.1
-    , time >= 1.9.1 && < 1.13
+    , text >= 1.2.5 && < 1.3 || >= 2.0 && < 2.1
+    , time >= 1.9.3 && < 1.13
   default-language: Haskell2010
   ghc-options:
     -Weverything
     -Wno-all-missed-specialisations
     -Wno-implicit-prelude
     -Wno-missed-specialisations
+    -Wno-missing-deriving-strategies
+    -Wno-missing-export-lists
     -Wno-missing-exported-signatures
+    -Wno-missing-safe-haskell-mode
+    -Wno-prepositive-qualified-module
     -Wno-redundant-constraints
     -Wno-safe
     -Wno-unsafe
 
-  if impl(ghc >= 8.4)
-    ghc-options:
-      -Wno-missing-export-lists
-
-  if impl(ghc >= 8.8)
-    ghc-options:
-      -Wno-missing-deriving-strategies
-
-  if impl(ghc >= 8.10)
-    ghc-options:
-      -Wno-missing-safe-haskell-mode
-      -Wno-prepositive-qualified-module
-
   if impl(ghc >= 9.2)
     ghc-options:
       -Wno-missing-kind-signatures
@@ -73,7 +64,7 @@
   import: library
 
   build-depends:
-    , template-haskell >= 2.12 && < 2.20
+    , template-haskell >= 2.17 && < 2.20
   exposed-modules:
     Witch
     Witch.Encoding
@@ -84,13 +75,6 @@
     Witch.TryFromException
     Witch.Utility
   hs-source-dirs: source/library
-
-  if impl(ghc >= 9.0)
-    hs-source-dirs: source/ghc-9.0
-  elif impl(ghc >= 8.10)
-    hs-source-dirs: source/ghc-8.10
-  else
-    hs-source-dirs: source/ghc-8.8
 
 test-suite witch-test-suite
   import: executable
