diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,6 +1,10 @@
 Changelog
 =========
 
+3.3.2
+------
+- GHC 8.4.1 compatibility.
+
 3.3.0
 ------
 - New `Semantic` typeclass that provides Traversals for SemVer-like data out
diff --git a/Data/Versions.hs b/Data/Versions.hs
--- a/Data/Versions.hs
+++ b/Data/Versions.hs
@@ -1,10 +1,11 @@
 {-# LANGUAGE Rank2Types #-}
 {-# LANGUAGE OverloadedStrings #-}
 {-# LANGUAGE DeriveGeneric, DeriveAnyClass #-}
+{-# LANGUAGE CPP #-}
 
 -- |
 -- Module    : Data.Versions
--- Copyright : (c) Colin Woodbury, 2015 - 2017
+-- Copyright : (c) Colin Woodbury, 2015 - 2018
 -- License   : BSD3
 -- Maintainer: Colin Woodbury <colingw@gmail.com>
 --
@@ -75,7 +76,6 @@
 import           Data.Char (isAlpha)
 import           Data.Hashable
 import           Data.List (intersperse)
-import           Data.Monoid
 import qualified Data.Text as T
 import           Data.Void
 import           Data.Word (Word)
@@ -83,6 +83,10 @@
 import           Text.Megaparsec
 import           Text.Megaparsec.Char
 
+#if __GLASGOW_HASKELL__ < 841
+import Data.Semigroup
+#endif
+
 ---
 
 -- | A top-level Versioning type. Acts as a wrapper for the more specific
@@ -285,11 +289,17 @@
             (_,[])  -> LT
             _       -> compare pr pr'
 
+instance Semigroup SemVer where
+  SemVer mj mn pa p m <> SemVer mj' mn' pa' p' m' =
+    SemVer (mj + mj') (mn + mn') (pa + pa') (p ++ p') (m ++ m')
+
 instance Monoid SemVer where
   mempty = SemVer 0 0 0 [] []
-  SemVer mj mn pa p m `mappend` SemVer mj' mn' pa' p' m' =
-    SemVer (mj + mj') (mn + mn') (pa + pa') (p ++ p') (m ++ m')
 
+#if __GLASGOW_HASKELL__ < 841
+  mappend = (<>)
+#endif
+
 instance Semantic SemVer where
   major f sv = fmap (\ma -> sv { _svMajor = ma }) (f $ _svMajor sv)
   {-# INLINE major #-}
@@ -314,13 +324,18 @@
 -- by periods in the source.
 data VUnit = Digits Word | Str T.Text deriving (Eq,Show,Read,Ord,Generic,NFData,Hashable)
 
+instance Semigroup VUnit where
+  Digits n <> Digits m = Digits $ n + m
+  Str t    <> Str s    = Str $ t <> s
+  Digits n <> _        = Digits n
+  _        <> Digits n = Digits n
+
 instance Monoid VUnit where
   mempty = Str ""
 
-  Digits n `mappend` Digits m = Digits $ n + m
-  Str t    `mappend` Str s    = Str $ t <> s
-  Digits n `mappend` _        = Digits n
-  _        `mappend` Digits n = Digits n
+#if __GLASGOW_HASKELL__ < 841
+  mappend = (<>)
+#endif
 
 -- | Smart constructor for a `VUnit` made of digits.
 digits :: Word -> VUnit
@@ -355,10 +370,15 @@
                        , _vChunks :: [VChunk]
                        , _vRel    :: [VChunk] } deriving (Eq,Show,Generic,NFData,Hashable)
 
+instance Semigroup Version where
+  Version e c r <> Version e' c' r' = Version ((+) <$> e <*> e') (c ++ c') (r ++ r')
+
 instance Monoid Version where
   mempty = Version Nothing [] []
 
-  Version e c r `mappend` Version e' c' r' = Version ((+) <$> e <*> e') (c ++ c') (r ++ r')
+#if __GLASGOW_HASKELL__ < 841
+  mappend = (<>)
+#endif
 
 -- | Set a `Version`'s epoch to `Nothing`.
 wipe :: Version -> Version
@@ -521,13 +541,18 @@
 -- if a previous one fails.
 newtype VParser = VParser { runVP :: T.Text -> Either ParsingError Versioning }
 
+instance Semigroup VParser where
+  -- | Will attempt the right parser if the left one fails.
+  (VParser f) <> (VParser g) = VParser h
+    where h t = either (const (g t)) Right $ f t
+
 instance Monoid VParser where
   -- | A parser which will always fail.
   mempty = VParser $ \_ -> Ideal <$> semver ""
 
-  -- | Will attempt the right parser if the left one fails.
-  (VParser f) `mappend` (VParser g) = VParser h
-    where h t = either (const (g t)) Right $ f t
+#if __GLASGOW_HASKELL__ < 841
+  mappend = (<>)
+#endif
 
 -- | Parse a piece of `T.Text` into either an (Ideal) `SemVer`, a (General)
 -- `Version`, or a (Complex) `Mess`.
diff --git a/Setup.hs b/Setup.hs
deleted file mode 100644
--- a/Setup.hs
+++ /dev/null
@@ -1,2 +0,0 @@
-import Distribution.Simple
-main = defaultMain
diff --git a/test/Test.hs b/test/Test.hs
--- a/test/Test.hs
+++ b/test/Test.hs
@@ -111,12 +111,13 @@
   , testGroup "Unit Tests"
     [ testGroup "(Ideal) Semantic Versioning"
       [ testGroup "Bad Versions (shouldn't parse)" $
-        map (\s -> testCase (unpack s) $ assert $ isLeft $ semver s) badSemVs
+        map (\s -> testCase (unpack s) $ assertBool "A bad version parsed" $ isLeft $ semver s) badSemVs
       , testGroup "Good Versions (should parse)" $
         map (\s -> testCase (unpack s) $ isomorphSV s) goodSemVs
       , testGroup "Comparisons" $
         testCase "1.2.3-alpha.2 == 1.2.3-alpha.2+a1b2c3.1"
-        (assert $ semver "1.2.3-alpha.2" == semver "1.2.3-alpha.2+a1b2c3.1") :
+        (assertBool "Equality test of two complicated SemVers failed"
+         $ semver "1.2.3-alpha.2" == semver "1.2.3-alpha.2+a1b2c3.1") :
         map (\(a,b) -> testCase (unpack $ a <> " < " <> b) $ comp semver a b)
         (zip semverOrd $ tail semverOrd)
       ]
@@ -189,7 +190,7 @@
 comp f a b = check $ (<) <$> f a <*> f b
 
 check :: Either a Bool -> Assertion
-check = assert . either (const False) id
+check = assertBool "Some Either-based assertion failed" . either (const False) id
 
 isSemVer :: Versioning -> Bool
 isSemVer (Ideal _) = True
diff --git a/versions.cabal b/versions.cabal
--- a/versions.cabal
+++ b/versions.cabal
@@ -1,17 +1,13 @@
--- This file has been generated from package.yaml by hpack version 0.17.1.
+-- This file has been generated from package.yaml by hpack version 0.20.0.
 --
 -- see: https://github.com/sol/hpack
+--
+-- hash: ade99e86a1b2ba008cc0e453113e07938d16e488a28e2f5fcdfb8b61e33d7a6c
 
 name:           versions
-version:        3.3.1
+version:        3.3.2
 synopsis:       Types and parsers for software version numbers.
-description:    A library for parsing and comparing software version numbers.
-                We like to give version numbers to our software in a myriad of
-                ways. Some ways follow strict guidelines for incrementing and comparison.
-                Some follow conventional wisdom and are generally self-consistent.
-                Some are just plain asinine. This library provides a means of parsing
-                and comparing /any/ style of versioning, be it a nice Semantic Version
-                like this:
+description:    A library for parsing and comparing software version numbers. We like to give version numbers to our software in a myriad of ways. Some ways follow strict guidelines for incrementing and comparison. Some follow conventional wisdom and are generally self-consistent. Some are just plain asinine. This library provides a means of parsing and comparing /any/ style of versioning, be it a nice Semantic Version like this:
                 .
                 > 1.2.3-r1+git123
                 .
@@ -19,14 +15,12 @@
                 .
                 > 2:10.2+0.0093r3+1-1
                 .
-                Please switch to <http://semver.org Semantic Versioning> if you
-                aren't currently using it. It provides consistency in version
-                incrementing and has the best constraints on comparisons.
-license:        BSD3
-license-file:   LICENSE
+                Please switch to <http://semver.org Semantic Versioning> if you aren't currently using it. It provides consistency in version incrementing and has the best constraints on comparisons.
+category:       Data
 author:         Colin Woodbury
 maintainer:     colingw@gmail.com
-category:       Data
+license:        BSD3
+license-file:   LICENSE
 build-type:     Simple
 cabal-version:  >= 1.10
 
@@ -39,31 +33,31 @@
   location: git://github.com/fosskers/haskell-versions.git
 
 library
+  ghc-options: -fwarn-unused-imports -fwarn-unused-binds -fwarn-name-shadowing -fwarn-unused-matches -fwarn-incomplete-patterns -Wincomplete-uni-patterns
+  build-depends:
+      base >=4.8 && <4.12
+    , deepseq >=1.4 && <1.5
+    , hashable >=1.2 && <1.3
+    , megaparsec >=6 && <7
+    , text >=1.2 && <1.3
   exposed-modules:
       Data.Versions
-  build-depends:
-      base >= 4.8 && < 4.11
-    , text >= 1.2 && < 1.3
-    , megaparsec >= 6 && < 7
-    , deepseq >= 1.4 && < 1.5
-    , hashable >= 1.2 && < 1.3
   default-language: Haskell2010
-  ghc-options: -fwarn-unused-imports -fwarn-unused-binds -fwarn-name-shadowing -fwarn-unused-matches -fwarn-incomplete-patterns -Wincomplete-uni-patterns
 
 test-suite versions-test
   type: exitcode-stdio-1.0
-  build-depends:
-      base >= 4.8 && < 4.11
-    , text >= 1.2 && < 1.3
-    , checkers >= 0.4 && < 0.5
-    , microlens >= 0.4 && < 0.5
-    , QuickCheck >= 2.9 && < 2.11
-    , tasty >= 0.10.1.2
-    , tasty-hunit >= 0.9.2
-    , tasty-quickcheck >= 0.8 && < 0.10
-    , versions
+  main-is: Test.hs
   hs-source-dirs:
       test
-  main-is: Test.hs
+  ghc-options: -fwarn-unused-imports -fwarn-unused-binds -fwarn-name-shadowing -fwarn-unused-matches -fwarn-incomplete-patterns -Wincomplete-uni-patterns -threaded -with-rtsopts=-N
+  build-depends:
+      QuickCheck >=2.9 && <2.12
+    , base >=4.8 && <4.12
+    , checkers >=0.4 && <0.5
+    , microlens >=0.4 && <0.5
+    , tasty >=0.10.1.2
+    , tasty-hunit >=0.9.2
+    , tasty-quickcheck >=0.8 && <0.10
+    , text >=1.2 && <1.3
+    , versions
   default-language: Haskell2010
-  ghc-options: -fwarn-unused-imports -fwarn-unused-binds -fwarn-name-shadowing -fwarn-unused-matches -fwarn-incomplete-patterns -Wincomplete-uni-patterns -threaded
