diff --git a/ChangeLog.md b/ChangeLog.md
--- a/ChangeLog.md
+++ b/ChangeLog.md
@@ -1,10 +1,17 @@
+# 0.0.0.4
+
+Support GHC 8.8.1 and loosen the bounds on `hashable` and `base`.
+
+
 # 0.0.0.3
 
 Support GHC 8.6 and its newer `containers` and `base`.
 
+
 # 0.0.0.2
 
 Add a `Lower` instance for `Data.Sequence.Seq`.
+
 
 # 0.0.0.1
 
diff --git a/semilattices.cabal b/semilattices.cabal
--- a/semilattices.cabal
+++ b/semilattices.cabal
@@ -1,5 +1,5 @@
 name:                semilattices
-version:             0.0.0.3
+version:             0.0.0.4
 synopsis:            Semilattices
 description:         Join- and meet-semilattices, with optional upper and lower bounds, and a variety of instances for each.
 homepage:            https://github.com/robrix/semilattices
@@ -7,7 +7,7 @@
 license-file:        LICENSE
 author:              Rob Rix
 maintainer:          rob.rix@me.com
-copyright:           2017-2018 Rob Rix
+copyright:           2017-2019 Rob Rix
 category:            Algebra, Data, Data Structures, Math
 build-type:          Simple
 cabal-version:       >=1.10
@@ -16,39 +16,55 @@
   README.md
   ChangeLog.md
 
-tested-with:         GHC == 8.2.2
-                   , GHC == 8.4.4
-                   , GHC == 8.6.2
+tested-with:
+  GHC   == 8.2.2
+  GHC   == 8.4.4
+  GHC   == 8.6.5
+  GHC   == 8.8.1
+  GHCJS == 8.4.0
 
 library
-  exposed-modules:     Data.Semilattice.Bound
-                     , Data.Semilattice.Join
-                     , Data.Semilattice.Lower
-                     , Data.Semilattice.Meet
-                     , Data.Semilattice.Order
-                     , Data.Semilattice.Tumble
-                     , Data.Semilattice.Upper
-  build-depends:       base >=4.9 && <4.13
-                     , containers >=0.5 && <0.7
-                     , hashable >=1.2 && <1.3
-                     , unordered-containers >=0.2 && <0.3
+  exposed-modules:
+    Data.Semilattice.Bound
+    Data.Semilattice.Join
+    Data.Semilattice.Lower
+    Data.Semilattice.Meet
+    Data.Semilattice.Order
+    Data.Semilattice.Tumble
+    Data.Semilattice.Upper
+  build-depends:
+      base >=4.9 && <5
+    , containers >=0.5 && <0.7
+    , hashable >=1.2 && <1.4
+    , unordered-containers >=0.2 && <0.3
   hs-source-dirs:      src
   default-language:    Haskell2010
-  ghc-options:         -Weverything -Wno-missing-local-signatures -Wno-missing-import-lists -Wno-implicit-prelude -Wno-safe -Wno-unsafe -Wno-name-shadowing -Wno-monomorphism-restriction -Wno-missed-specialisations -Wno-all-missed-specialisations
-  if (impl(ghc >= 8.4))
-    ghc-options:       -Wno-missing-export-lists
+  ghc-options:
+    -Weverything
+    -Wno-all-missed-specialisations
+    -Wno-implicit-prelude
+    -Wno-missed-specialisations
+    -Wno-missing-import-lists
+    -Wno-missing-local-signatures
+    -Wno-monomorphism-restriction
+    -Wno-name-shadowing
+    -Wno-safe
+    -Wno-unsafe
   if (impl(ghc >= 8.6))
-    ghc-options:       -Wno-star-is-type
+    ghc-options: -Wno-star-is-type
+  if (impl(ghc >= 8.8))
+    ghc-options: -Wno-missing-deriving-strategies
 
 test-suite doctests
   type:                exitcode-stdio-1.0
   hs-source-dirs:      test
   main-is:             Doctests.hs
   default-language:    Haskell2010
-  build-depends:       base
-                     , doctest >= 0.7 && < 1.0
-                     , QuickCheck >= 2.7 && < 2.12
-                     , quickcheck-instances == 0.3.*
+  build-depends:
+      base
+    , doctest >= 0.7 && < 1.0
+    , QuickCheck >= 2.7 && < 3
+    , quickcheck-instances == 0.3.*
 
 source-repository head
   type:     git
diff --git a/src/Data/Semilattice/Bound.hs b/src/Data/Semilattice/Bound.hs
--- a/src/Data/Semilattice/Bound.hs
+++ b/src/Data/Semilattice/Bound.hs
@@ -1,6 +1,8 @@
 {-# LANGUAGE DeriveTraversable, GeneralizedNewtypeDeriving #-}
 -- | 'Lower' and 'Upper' bounds from 'Bounded' instances.
-module Data.Semilattice.Bound where
+module Data.Semilattice.Bound
+( Bound(..)
+) where
 
 import Data.Semilattice.Lower
 import Data.Semilattice.Upper
diff --git a/src/Data/Semilattice/Join.hs b/src/Data/Semilattice/Join.hs
--- a/src/Data/Semilattice/Join.hs
+++ b/src/Data/Semilattice/Join.hs
@@ -1,5 +1,5 @@
 {-# LANGUAGE DeriveTraversable, GeneralizedNewtypeDeriving #-}
--- | Join semilattices, related to 'Lower' and 'Upper'.
+-- | Join semilattices, related to 'Lower' and 'Data.Semilattice.Upper.Upper'.
 module Data.Semilattice.Join
 ( Join(..)
 , Joining(..)
@@ -47,11 +47,11 @@
   -- a '\/' 'lowerBound' = a
   -- @
   --
-  --   If @s@ has an 'Upper' bound, then 'upperBound' must be its absorbing element:
+  --   If @s@ has an 'Data.Semilattice.Upper.Upper' bound, then 'Data.Semilattice.Upper.upperBound' must be its absorbing element:
   --
   -- @
-  -- 'upperBound' '\/' a = 'upperBound'
-  -- a '\/' 'upperBound' = 'upperBound'
+  -- 'Data.Semilattice.Upper.upperBound' '\/' a = 'Data.Semilattice.Upper.upperBound'
+  -- a '\/' 'Data.Semilattice.Upper.upperBound' = 'Data.Semilattice.Upper.upperBound'
   -- @
   (\/) :: s -> s -> s
 
diff --git a/src/Data/Semilattice/Lower.hs b/src/Data/Semilattice/Lower.hs
--- a/src/Data/Semilattice/Lower.hs
+++ b/src/Data/Semilattice/Lower.hs
@@ -1,6 +1,8 @@
 {-# LANGUAGE CPP, DefaultSignatures, PolyKinds, TypeFamilies, TypeOperators #-}
--- | Lower bounds, related to 'Bounded', 'Join', 'Meet', and 'Ord'.
-module Data.Semilattice.Lower where
+-- | Lower bounds, related to 'Bounded', 'Data.Semilattice.Join.Join', 'Data.Semilattice.Meet.Meet', and 'Ord'.
+module Data.Semilattice.Lower
+( Lower(..)
+) where
 
 import Data.Char
 import Data.Coerce
@@ -35,16 +37,16 @@
 -- 'lowerBound' = 'minBound'
 -- @
 --
---   If @s@ is a 'Join' semilattice, 'lowerBound' must be the identity of '\/':
+--   If @s@ is a 'Data.Semilattice.Join.Join' semilattice, 'lowerBound' must be the identity of 'Data.Semilattice.Join.\/':
 --
 -- @
--- 'lowerBound' '\/' a = a
+-- 'lowerBound' 'Data.Semilattice.Join.\/' a = a
 -- @
 --
---   If @s@ is a 'Meet' semilattice, 'lowerBound' must be the absorbing element of '/\':
+--   If @s@ is a 'Data.Semilattice.Meet.Meet' semilattice, 'lowerBound' must be the absorbing element of 'Data.Semilattice.Meet./\':
 --
 -- @
--- 'lowerBound' '/\' a = 'lowerBound'
+-- 'lowerBound' 'Data.Semilattice.Meet./\' a = 'lowerBound'
 -- @
 --
 --   If @s@ is 'Ord'ered, 'lowerBound' must be at least as small as every terminating value:
@@ -67,11 +69,11 @@
 --
 -- prop> lowerBound == (minBound :: Bool)
 --
--- Identity of '\/':
+-- Identity of 'Data.Semilattice.Join.\/':
 --
 -- prop> lowerBound \/ a == (a :: Bool)
 --
--- Absorbing element of '/\':
+-- Absorbing element of 'Data.Semilattice.Meet./\':
 --
 -- prop> lowerBound /\ a == (lowerBound :: Bool)
 --
@@ -207,7 +209,9 @@
 instance Lower CId
 instance Lower CFsFilCnt
 instance Lower CFsBlkCnt
+#ifdef HTYPE_CLOCKID_T
 instance Lower CClockId
+#endif
 instance Lower CBlkCnt
 instance Lower CBlkSize
 #endif
diff --git a/src/Data/Semilattice/Meet.hs b/src/Data/Semilattice/Meet.hs
--- a/src/Data/Semilattice/Meet.hs
+++ b/src/Data/Semilattice/Meet.hs
@@ -1,5 +1,5 @@
 {-# LANGUAGE DeriveTraversable, GeneralizedNewtypeDeriving #-}
--- | Join semilattices, related to 'Lower' and 'Upper'.
+-- | Join semilattices, related to 'Data.Semilattice.Lower.Lower' and 'Upper'.
 module Data.Semilattice.Meet
 ( Meet(..)
 , Meeting(..)
@@ -47,11 +47,11 @@
   -- a '/\' 'upperBound' = a
   -- @
   --
-  --   If @s@ has a 'Lower' bound, then 'lowerBound' must be its absorbing element:
+  --   If @s@ has a 'Data.Semilattice.Lower.Lower' bound, then 'Data.Semilattice.Lower.lowerBound' must be its absorbing element:
   --
   -- @
-  -- 'lowerBound' '/\' a = 'lowerBound'
-  -- a '/\' 'lowerBound' = 'lowerBound'
+  -- 'Data.Semilattice.Lower.lowerBound' '/\' a = 'Data.Semilattice.Lower.lowerBound'
+  -- a '/\' 'Data.Semilattice.Lower.lowerBound' = 'Data.Semilattice.Lower.lowerBound'
   -- @
   (/\) :: s -> s -> s
 
diff --git a/src/Data/Semilattice/Order.hs b/src/Data/Semilattice/Order.hs
--- a/src/Data/Semilattice/Order.hs
+++ b/src/Data/Semilattice/Order.hs
@@ -1,6 +1,8 @@
 {-# LANGUAGE DeriveTraversable, GeneralizedNewtypeDeriving #-}
 -- | Total 'Ord'erings give rise to 'Join' and 'Meet' semilattices.
-module Data.Semilattice.Order where
+module Data.Semilattice.Order
+( Order(..)
+) where
 
 import Data.Semilattice.Join
 import Data.Semilattice.Lower
diff --git a/src/Data/Semilattice/Tumble.hs b/src/Data/Semilattice/Tumble.hs
--- a/src/Data/Semilattice/Tumble.hs
+++ b/src/Data/Semilattice/Tumble.hs
@@ -1,6 +1,8 @@
 {-# LANGUAGE DeriveTraversable, GeneralizedNewtypeDeriving #-}
 -- | Inverting a 'Join' semilattice gives rise to a 'Meet' semilattice, and vice versa.
-module Data.Semilattice.Tumble where
+module Data.Semilattice.Tumble
+( Tumble(..)
+) where
 
 import Data.Semilattice.Join
 import Data.Semilattice.Lower
diff --git a/src/Data/Semilattice/Upper.hs b/src/Data/Semilattice/Upper.hs
--- a/src/Data/Semilattice/Upper.hs
+++ b/src/Data/Semilattice/Upper.hs
@@ -1,6 +1,8 @@
 {-# LANGUAGE CPP, DefaultSignatures, PolyKinds, TypeFamilies, TypeOperators #-}
--- | Upper bounds, related to 'Bounded', 'Join', 'Meet', and 'Ord'.
-module Data.Semilattice.Upper where
+-- | Upper bounds, related to 'Bounded', 'Data.Semilattice.Join.Join', 'Data.Semilattice.Meet.Meet', and 'Ord'.
+module Data.Semilattice.Upper
+( Upper(..)
+) where
 
 import Data.Char
 import Data.Coerce
@@ -28,16 +30,16 @@
 -- 'upperBound' = 'maxBound'
 -- @
 --
---   If @s@ is a 'Meet' semilattice, 'upperBound' must be the identity of '/\':
+--   If @s@ is a 'Data.Semilattice.Meet.Meet' semilattice, 'upperBound' must be the identity of 'Data.Semilattice.Meet./\':
 --
 -- @
--- 'upperBound' '/\' a = a
+-- 'upperBound' 'Data.Semilattice.Meet./\' a = a
 -- @
 --
---   If @s@ is a 'Join' semilattice, 'upperBound' must be the absorbing element of '\/':
+--   If @s@ is a 'Data.Semilattice.Join.Join' semilattice, 'upperBound' must be the absorbing element of 'Data.Semilattice.Join.\/':
 --
 -- @
--- 'upperBound' '\/' a = 'upperBound'
+-- 'upperBound' 'Data.Semilattice.Join.\/' a = 'upperBound'
 -- @
 --
 --   If @s@ is 'Ord'ered, 'upperBound' must be at least as large as every terminating value:
@@ -60,11 +62,11 @@
 --
 -- prop> upperBound == (maxBound :: Bool)
 --
--- Identity of '/\':
+-- Identity of 'Data.Semilattice.Meet./\':
 --
 -- prop> upperBound /\ a == (a :: Bool)
 --
--- Absorbing element of '\/':
+-- Absorbing element of 'Data.Semilattice.Join.\/':
 --
 -- prop> upperBound \/ a == (upperBound :: Bool)
 --
@@ -193,7 +195,9 @@
 instance Upper CId
 instance Upper CFsFilCnt
 instance Upper CFsBlkCnt
+#ifdef HTYPE_CLOCKID_T
 instance Upper CClockId
+#endif
 instance Upper CBlkCnt
 instance Upper CBlkSize
 #endif
