diff --git a/.hlint.yaml b/.hlint.yaml
--- a/.hlint.yaml
+++ b/.hlint.yaml
@@ -1,4 +1,4 @@
-- arguments: [--cpp-define=HLINT, --cpp-ansi]
+- arguments: [-XCPP, --cpp-define=HLINT, --cpp-ansi]
 
 - ignore: {name: Use camelCase}
 - ignore: {name: Missing NOINLINE pragma}
diff --git a/CHANGELOG.markdown b/CHANGELOG.markdown
--- a/CHANGELOG.markdown
+++ b/CHANGELOG.markdown
@@ -1,3 +1,7 @@
+0.8.3 [2025.03.03]
+------------------
+* Drop support for pre-8.0 versions of GHC.
+
 0.8.2 [2021.06.28]
 ------------------
 * `Embed` flag is now `True` by default to resolve unexpected issues with standalone applications [#18](https://github.com/ekmett/hyphenation/issues/18)
diff --git a/hyphenation.cabal b/hyphenation.cabal
--- a/hyphenation.cabal
+++ b/hyphenation.cabal
@@ -1,6 +1,6 @@
 name:          hyphenation
 category:      Text
-version:       0.8.2
+version:       0.8.3
 license:       BSD2
 cabal-version: >= 1.10
 license-file:  LICENSE
@@ -11,16 +11,19 @@
 bug-reports:   http://github.com/ekmett/hyphenation/issues
 copyright:     (C) 2012-2019 Edward A. Kmett
 synopsis:      Configurable Knuth-Liang hyphenation
-tested-with:   GHC == 7.6.3
-             , GHC == 7.8.4
-             , GHC == 7.10.3
-             , GHC == 8.0.2
+tested-with:   GHC == 8.0.2
              , GHC == 8.2.2
              , GHC == 8.4.4
              , GHC == 8.6.5
              , GHC == 8.8.4
-             , GHC == 8.10.4
-             , GHC == 9.0.1
+             , GHC == 8.10.7
+             , GHC == 9.0.2
+             , GHC == 9.2.8
+             , GHC == 9.4.8
+             , GHC == 9.6.6
+             , GHC == 9.8.4
+             , GHC == 9.10.1
+             , GHC == 9.12.1
 description:
   Configurable Knuth-Liang hyphenation
   .
@@ -49,7 +52,7 @@
 
 source-repository head
   type: git
-  location: git://github.com/ekmett/hyphenation.git
+  location: https://github.com/ekmett/hyphenation.git
 
 Flag Embed
   Description: Embed data in library binary
@@ -60,16 +63,13 @@
 
 library
   build-depends:
-    base                 >= 4       && < 5,
-    bytestring           >= 0.9     && < 0.12,
-    containers           >= 0.3.0.0 && < 0.7,
-    unordered-containers >= 0.2.1   && < 0.3,
-    zlib                 >= 0.5     && < 0.7,
+    base                 >= 4.9      && < 5,
+    bytestring           >= 0.10.8.1 && < 0.13,
+    containers           >= 0.3.0.0  && < 0.9,
+    unordered-containers >= 0.2.1    && < 0.3,
+    zlib                 >= 0.5      && < 0.8,
     text
 
-  if !impl(ghc>=7.11)
-    build-depends: semigroups >= 0.16 && < 0.20
-
   if flag(embed)
     build-depends: file-embed >= 0.0.7 && < 0.1
     CPP-Options: "-DEMBED"
@@ -82,7 +82,6 @@
    Text.Hyphenation.Pattern
 
   other-modules:
-   Text.Hyphenation.ByteStringLazyCompat
    Paths_hyphenation
 
   hs-source-dirs: src
diff --git a/src/Text/Hyphenation/ByteStringLazyCompat.hs b/src/Text/Hyphenation/ByteStringLazyCompat.hs
deleted file mode 100644
--- a/src/Text/Hyphenation/ByteStringLazyCompat.hs
+++ /dev/null
@@ -1,32 +0,0 @@
-{-# LANGUAGE CPP #-}
-
------------------------------------------------------------------------------
--- |
--- Module      :  Text.Hyphenation.ByteStringLazyCompat
--- Copyright   :  (C) 2012-2019 Edward Kmett,
---                (C) 2007 Ned Batchelder
--- License     :  BSD-style (see the languageAffix LICENSE)
---
--- Maintainer  :  Edward Kmett <ekmett@gmail.com>
--- Stability   :  provisional
--- Portability :  portable
---
-----------------------------------------------------------------------------
-module Text.Hyphenation.ByteStringLazyCompat
-  ( module Lazy
-#if !(MIN_VERSION_bytestring(0,10,0))
-  , fromStrict
-#endif
-  ) where
-
-import Data.ByteString.Lazy as Lazy
-
-#if !(MIN_VERSION_bytestring(0,10,0))
-import qualified Data.ByteString as BS
-import Data.ByteString.Lazy.Internal (ByteString(..))
-
--- |/O(1)/ Convert a strict 'ByteString' into a lazy 'ByteString'.
-fromStrict :: BS.ByteString -> ByteString
-fromStrict bs | BS.null bs = Empty
-              | otherwise = Chunk bs Empty
-#endif
diff --git a/src/Text/Hyphenation/Exception.hs b/src/Text/Hyphenation/Exception.hs
--- a/src/Text/Hyphenation/Exception.hs
+++ b/src/Text/Hyphenation/Exception.hs
@@ -24,10 +24,6 @@
 import qualified Data.HashMap.Strict as HM
 import Prelude hiding (lookup)
 
-#if !(MIN_VERSION_base(4,8,0))
-import Data.Monoid (Monoid(..))
-#endif
-
 #if !(MIN_VERSION_base(4,11,0))
 import Data.Semigroup (Semigroup(..))
 #endif
@@ -68,7 +64,9 @@
 scoreException :: String -> [Int]
 scoreException []         = [0]
 scoreException (x:ys)
-  | x == '-'  = 1 : if null ys then [] else scoreException (tail ys)
+  | x == '-'  = 1 : case ys of
+                      []    -> []
+                      _:ys' -> scoreException ys'
   | otherwise = 0 : scoreException ys
 
 -- | Parse one exception per line from an input string
diff --git a/src/Text/Hyphenation/Hyphenator.hs b/src/Text/Hyphenation/Hyphenator.hs
--- a/src/Text/Hyphenation/Hyphenator.hs
+++ b/src/Text/Hyphenation/Hyphenator.hs
@@ -52,7 +52,12 @@
 -- >>> hyphenate english_US "hyphenation"
 -- ["hy","phen","ation"]
 hyphenate :: Hyphenator -> String -> [String]
-hyphenate h s0 = go [] s0 $ tail $ hyphenationScore h s0 where
+hyphenate h s0 = go [] s0 score' where
+  score' =
+    case hyphenationScore h s0 of
+      _:ps -> ps
+      []   -> error $ "Malformed hyphenation score for " ++ s0
+
   go acc (w:ws) (p:ps)
     | odd p     = reverse (w:acc) : go [] ws ps
     | otherwise = go (w:acc) ws ps
diff --git a/src/Text/Hyphenation/Language.hs b/src/Text/Hyphenation/Language.hs
--- a/src/Text/Hyphenation/Language.hs
+++ b/src/Text/Hyphenation/Language.hs
@@ -1,7 +1,5 @@
 {-# LANGUAGE CPP #-}
-#if __GLASGOW_HASKELL__ >= 702
 {-# LANGUAGE Trustworthy #-}
-#endif
 #if EMBED
 {-# LANGUAGE TemplateHaskell #-}
 #endif
@@ -38,13 +36,10 @@
   ) where
 
 import Codec.Compression.GZip
-#if __GLASGOW_HASKELL__ < 710
-import Data.Functor ((<$>))
-#endif
+import qualified Data.ByteString.Lazy as Lazy
 import qualified Data.IntMap as IM
 import qualified Data.Text as T
 import qualified Data.Text.Encoding as T
-import Text.Hyphenation.ByteStringLazyCompat as Lazy
 import Text.Hyphenation.Hyphenator
 import Text.Hyphenation.Pattern
 import Text.Hyphenation.Exception
@@ -85,15 +80,19 @@
 #else
 loadHyphenator language = return $ Hyphenator tryLookup (parsePatterns pat) (parseExceptions hyp) defaultLeftMin defaultRightMin
   where affix = languageAffix language
-        Just hyp = unzipUtf8 . Lazy.fromStrict <$> lookup ("hyph-" ++ affix ++ ".hyp.txt.gz") hyphenatorFiles
-        Just pat = unzipUtf8 . Lazy.fromStrict <$> lookup ("hyph-" ++ affix ++ ".pat.txt.gz") hyphenatorFiles
-        Just chr = unzipUtf8 . Lazy.fromStrict <$> lookup ("hyph-" ++ affix ++ ".chr.txt.gz") hyphenatorFiles
+        lookupHyphenatorFile fileName =
+          case lookup fileName hyphenatorFiles of
+            Just contents -> contents
+            Nothing       -> error $ "Could not find " ++ fileName
+        hyp = unzipUtf8 $ Lazy.fromStrict $ lookupHyphenatorFile $ "hyph-" ++ affix ++ ".hyp.txt.gz"
+        pat = unzipUtf8 $ Lazy.fromStrict $ lookupHyphenatorFile $ "hyph-" ++ affix ++ ".pat.txt.gz"
+        chr = unzipUtf8 $ Lazy.fromStrict $ lookupHyphenatorFile $ "hyph-" ++ affix ++ ".chr.txt.gz"
         chrMap = IM.fromList (Prelude.lines chr >>= chrLine)
         (defaultLeftMin, defaultRightMin) = languageMins language
         tryLookup x = IM.findWithDefault x (fromEnum x) chrMap
 #endif
 
-unzipUtf8 :: ByteString -> String
+unzipUtf8 :: Lazy.ByteString -> String
 unzipUtf8 =
   T.unpack . T.decodeUtf8With (\ _ -> fmap (toEnum . fromEnum))
   . Lazy.toStrict . decompress
diff --git a/src/Text/Hyphenation/Pattern.hs b/src/Text/Hyphenation/Pattern.hs
--- a/src/Text/Hyphenation/Pattern.hs
+++ b/src/Text/Hyphenation/Pattern.hs
@@ -25,10 +25,6 @@
 import Prelude hiding (lookup)
 import Data.Char (digitToInt, isDigit)
 
-#if !(MIN_VERSION_base(4,8,0))
-import Data.Monoid (Monoid(..))
-#endif
-
 #if !(MIN_VERSION_base(4,11,0))
 import Data.Semigroup (Semigroup(..))
 #endif
@@ -48,7 +44,17 @@
 
 -- | Tallies the hyphenation scores for a word considering all tails.
 lookupPattern :: String -> Patterns -> [Int]
-lookupPattern xs0 = init . tail . go ('.' : xs0 ++ ".") where
+lookupPattern xs0 p = scores1 where
+  scores0 =
+    case go ('.' : xs0 ++ ".") p of
+      _:ys -> ys
+      [] -> error $ "lookupPattern.scores0: Impossible (" ++ xs0 ++ ")"
+
+  scores1 =
+    case unsnoc scores0 of
+      Just (ys, _) -> ys
+      Nothing -> error $ "lookupPattern.scores1: Impossible (" ++ xs0 ++ ")"
+
   go [] (Patterns ys _) = ys
   go xxs@(_:xs) t = zipMax (go1 xxs t) (0:go xs t)
   go1 [] (Patterns ys _) = ys
@@ -87,7 +93,9 @@
 scorePattern :: String -> [Int]
 scorePattern [] = [0]
 scorePattern (x:ys)
-  | isDigit x = digitToInt x : if null ys then [] else scorePattern (tail ys)
+  | isDigit x = digitToInt x : case ys of
+                                 []    -> []
+                                 _:ys' -> scorePattern ys'
   | otherwise = 0 : scorePattern ys
 
 -- | Zip two scores.
@@ -96,3 +104,9 @@
 zipMax [] ys = ys
 zipMax xs [] = xs
 
+-- | Decompose a list into 'init' and 'last'.
+unsnoc :: [a] -> Maybe ([a], a)
+unsnoc []     = Nothing
+unsnoc (x:xs) = case unsnoc xs of
+                  Nothing    -> Just ([], x)
+                  Just (a,b) -> Just (x:a, b)
