diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,21 @@
+# 0.3.0.0
+
+- Added laws for the following factorial semigroup and monoid classes:
+    - `Data.Semigroup.Factorial.Factorial`
+    - `Data.Semigroup.Factorial.StableFactorial`
+    - `Data.Monoid.Factorial.FactorialMonoid`
+
+- Added laws for the following GCD and LCM monoid classes:
+    - `Data.Monoid.GCD.{Left,Right}DistributiveGCDMonoid`
+    - `Data.Monoid.GCD.DistributiveGCDMonoid`
+    - `Data.Monoid.LCM.DistributiveLCMMonoid`
+
+- Added missing laws for the following class:
+    - `Data.Monoid.GCD.OverlappingGCDMonoid`
+
+- Removed `cancellativeGCDMonoidLaws`.
+    - The documentation for the `GCDMonoid` class no longer states these laws.
+
 # 0.2.0.0
 
 - Improved generation of arbitrary `Semigroup` value combinations.
diff --git a/README.md b/README.md
--- a/README.md
+++ b/README.md
@@ -56,17 +56,23 @@
 > import Numeric.Natural (Natural)
 > import Test.QuickCheck.Classes
 > import Test.QuickCheck.Classes.Monoid.GCD
+> import Test.QuickCheck.Classes.Monoid.LCM
 > import Test.QuickCheck.Classes.Monoid.Monus
 > import Test.QuickCheck.Classes.Monoid.Null
 > import Test.QuickCheck.Classes.Semigroup.Cancellative
+> import Test.QuickCheck.Classes.Semigroup.Factorial
 >
 > lawsCheckOne (Proxy :: Proxy (Sum Natural))
->     [ cancellativeGCDMonoidLaws
->     , cancellativeLaws
+>     [ cancellativeLaws
 >     , commutativeLaws
+>     , distributiveGCDMonoidLaws
+>     , distributiveLCMMonoidLaws
+>     , factorialLaws
+>     , factorialMonoidLaws
 >     , gcdMonoidLaws
 >     , lcmMonoidLaws
 >     , leftCancellativeLaws
+>     , leftDistributiveGCDMonoidLaws
 >     , leftGCDMonoidLaws
 >     , leftReductiveLaws
 >     , monoidLaws
@@ -76,9 +82,11 @@
 >     , positiveMonoidLaws
 >     , reductiveLaws
 >     , rightCancellativeLaws
+>     , rightDistributiveGCDMonoidLaws
 >     , rightGCDMonoidLaws
 >     , rightReductiveLaws
 >     , semigroupLaws
+>     , stableFactorialLaws
 >     ]
 > ```
 
diff --git a/quickcheck-monoid-subclasses.cabal b/quickcheck-monoid-subclasses.cabal
--- a/quickcheck-monoid-subclasses.cabal
+++ b/quickcheck-monoid-subclasses.cabal
@@ -1,6 +1,6 @@
 cabal-version:  3.0
 name:           quickcheck-monoid-subclasses
-version:        0.2.0.0
+version:        0.3.0.0
 bug-reports:    https://github.com/jonathanknowles/quickcheck-monoid-subclasses/issues
 license:        Apache-2.0
 license-file:   LICENSE
@@ -29,7 +29,7 @@
 common dependency-hspec
     build-depends:hspec                     >= 2.10.7       && < 2.11
 common dependency-monoid-subclasses
-    build-depends:monoid-subclasses         >= 1.2.2        && < 1.3
+    build-depends:monoid-subclasses         >= 1.2.3        && < 1.3
 common dependency-pretty-show
     build-depends:pretty-show               >= 1.10         && < 1.11
 common dependency-QuickCheck
@@ -77,11 +77,13 @@
     hs-source-dirs:
         src/public
     exposed-modules:
+        Test.QuickCheck.Classes.Monoid.Factorial
         Test.QuickCheck.Classes.Monoid.GCD
         Test.QuickCheck.Classes.Monoid.LCM
         Test.QuickCheck.Classes.Monoid.Monus
         Test.QuickCheck.Classes.Monoid.Null
         Test.QuickCheck.Classes.Semigroup.Cancellative
+        Test.QuickCheck.Classes.Semigroup.Factorial
 
 library internal
     import:
diff --git a/src/internal/Internal/Semigroup/Tuple.hs b/src/internal/Internal/Semigroup/Tuple.hs
--- a/src/internal/Internal/Semigroup/Tuple.hs
+++ b/src/internal/Internal/Semigroup/Tuple.hs
@@ -60,6 +60,7 @@
 instance Show VariableSum where
     show (VariableSum vs) = F1.intercalate1 " <> " $ show <$> vs
 
+a, b, c, d :: VariableSum
 a = VariableSum (A :| [])
 b = VariableSum (B :| [])
 c = VariableSum (C :| [])
diff --git a/src/public/Test/QuickCheck/Classes/Monoid/Factorial.hs b/src/public/Test/QuickCheck/Classes/Monoid/Factorial.hs
new file mode 100644
--- /dev/null
+++ b/src/public/Test/QuickCheck/Classes/Monoid/Factorial.hs
@@ -0,0 +1,408 @@
+{- HLINT ignore "Avoid lambda" -}
+{- HLINT ignore "Hoist not" -}
+{- HLINT ignore "Redundant bracket" -}
+{- HLINT ignore "Use camelCase" -}
+{- HLINT ignore "Use const" -}
+
+-- |
+-- Copyright: © 2022–2023 Jonathan Knowles
+-- License: Apache-2.0
+--
+-- This module provides 'Laws' definitions for classes exported by
+-- "Data.Monoid.Factorial".
+--
+module Test.QuickCheck.Classes.Monoid.Factorial
+    ( factorialMonoidLaws
+    )
+    where
+
+import Prelude hiding
+    ( dropWhile, foldl, length, null, reverse, span, splitAt, takeWhile )
+
+import Data.Bifunctor
+    ( Bifunctor (bimap) )
+import Data.Function
+    ( (&) )
+import Data.List
+    ( unfoldr )
+import Data.Monoid.Factorial
+    ( FactorialMonoid
+    , inits
+    , span
+    , split
+    , splitAt
+    , splitPrimePrefix
+    , splitPrimeSuffix
+    , tails
+    )
+import Data.Monoid.Null
+    ( null )
+import Data.Proxy
+    ( Proxy )
+import Data.Semigroup.Factorial
+    ( factors, length, primePrefix, primeSuffix, reverse )
+import Data.Tuple
+    ( swap )
+import Internal
+    ( cover, makeLaw1, makeProperty, report )
+import Test.QuickCheck
+    ( Arbitrary (arbitrary, shrink)
+    , Fun
+    , Property
+    , Testable
+    , applyFun
+    , chooseInt
+    , elements
+    , forAll
+    , forAllShrink
+    )
+import Test.QuickCheck.Classes
+    ( Laws (Laws) )
+
+import qualified Data.List as L
+
+--------------------------------------------------------------------------------
+-- FactorialMonoid
+--------------------------------------------------------------------------------
+
+-- | 'Laws' for instances of 'FactorialMonoid'.
+--
+-- Includes the following laws:
+--
+-- @
+-- 'null' a '==' 'null' ('factors' a)
+-- @
+--
+-- @
+-- 'factors' a '==' \ \ \     \ ('unfoldr'  \    \ \    \   'splitPrimePrefix'  a)
+-- 'factors' a '==' 'L.reverse' ('unfoldr' ('fmap' 'swap' . 'splitPrimeSuffix') a)
+-- @
+--
+-- @
+-- 'reverse' a '==' 'mconcat' ('L.reverse' ('factors' a))
+-- @
+--
+-- @
+-- 'primePrefix' a '==' 'maybe' 'mempty' 'fst' ('splitPrimePrefix' a)
+-- 'primeSuffix' a '==' 'maybe' 'mempty' 'snd' ('splitPrimeSuffix' a)
+-- @
+--
+-- @
+-- 'inits' a '==' 'fmap' 'mconcat' ('L.inits' ('factors' a))
+-- 'tails' a '==' 'fmap' 'mconcat' ('L.tails' ('factors' a))
+-- @
+--
+-- @
+-- 'span' p a '==' 'bimap' 'mconcat' 'mconcat' ('L.span' p ('factors' a))
+-- @
+--
+-- @
+-- 'L.all' ('L.all' ('not' . p) . 'factors') ('split' p a)
+-- @
+--
+-- @
+-- 'mconcat' ('L.intersperse' p ('split' ('==' p) a)) '==' a
+-- @
+--
+-- @
+-- 'splitAt' i a '==' 'bimap' 'mconcat' 'mconcat' ('L.splitAt' i ('factors' a))
+-- @
+--
+-- Note that the following superclass laws are __not__ included:
+--
+-- * 'Test.QuickCheck.Classes.Semigroup.Factorial.factorialLaws'
+-- * 'Test.QuickCheck.Classes.Monoid.Null.monoidNullLaws'
+--
+factorialMonoidLaws
+    :: forall a. (Arbitrary a, Show a, Eq a, FactorialMonoid a)
+    => Proxy a
+    -> Laws
+factorialMonoidLaws _ = Laws "FactorialMonoid"
+    [ makeLaw1 @a
+        "factorialMonoidLaw_coverage"
+        (factorialMonoidLaw_coverage)
+    , makeLaw1 @a
+        "factorialMonoidLaw_null"
+        (factorialMonoidLaw_null)
+    , makeLaw1 @a
+        "factorialMonoidLaw_splitPrimePrefix"
+        (factorialMonoidLaw_splitPrimePrefix)
+    , makeLaw1 @a
+        "factorialMonoidLaw_splitPrimeSuffix"
+        (factorialMonoidLaw_splitPrimeSuffix)
+    , makeLaw1 @a
+        "factorialMonoidLaw_reverse"
+        (factorialMonoidLaw_reverse)
+    , makeLaw1 @a
+        "factorialMonoidLaw_primePrefix"
+        (factorialMonoidLaw_primePrefix)
+    , makeLaw1 @a
+        "factorialMonoidLaw_primeSuffix"
+        (factorialMonoidLaw_primeSuffix)
+    , makeLaw1 @a
+        "factorialMonoidLaw_inits"
+        (factorialMonoidLaw_inits)
+    , makeLaw1 @a
+        "factorialMonoidLaw_tails"
+        (factorialMonoidLaw_tails)
+    , makeLaw1 @a
+        "factorialMonoidLaw_span"
+        (factorialMonoidLaw_span)
+    , makeLaw1 @a
+        "factorialMonoidLaw_split"
+        (factorialMonoidLaw_split)
+    , makeLaw1 @a
+        "factorialMonoidLaw_split_intersperse"
+        (factorialMonoidLaw_split_intersperse)
+    , makeLaw1 @a
+        "factorialMonoidLaw_splitAt"
+        (factorialMonoidLaw_splitAt)
+    ]
+
+factorialMonoidLaw_coverage
+    :: (Eq a, Show a, FactorialMonoid a) => a -> Property
+factorialMonoidLaw_coverage a =
+    makeProperty
+        "True"
+        (True)
+    & cover
+        "length a == 0"
+        (length a == 0)
+    & cover
+        "length a == 1"
+        (length a == 1)
+    & cover
+        "length a >= 2"
+        (length a >= 2)
+
+factorialMonoidLaw_null
+    :: (Eq a, Show a, FactorialMonoid a) => a -> Property
+factorialMonoidLaw_null a =
+    makeProperty
+        "null a == null (factors a)"
+        (null a == null (factors a))
+    & report
+        "null a"
+        (null a)
+    & report
+        "factors a"
+        (factors a)
+    & report
+        "null (factors a)"
+        (null (factors a))
+
+factorialMonoidLaw_splitPrimePrefix
+    :: (Eq a, Show a, FactorialMonoid a) => a -> Property
+factorialMonoidLaw_splitPrimePrefix a =
+    makeProperty
+        "factors a == unfoldr splitPrimePrefix a"
+        (factors a == unfoldr splitPrimePrefix a)
+    & report
+        "factors a"
+        (factors a)
+    & report
+        "unfoldr splitPrimePrefix a"
+        (unfoldr splitPrimePrefix a)
+
+factorialMonoidLaw_splitPrimeSuffix
+    :: (Eq a, Show a, FactorialMonoid a) => a -> Property
+factorialMonoidLaw_splitPrimeSuffix a =
+    makeProperty
+        "factors a == L.reverse (unfoldr (fmap swap . splitPrimeSuffix) a)"
+        (factors a == L.reverse (unfoldr (fmap swap . splitPrimeSuffix) a))
+    & report
+        "factors a"
+        (factors a)
+    & report
+        "unfoldr (fmap swap . splitPrimeSuffix) a"
+        (unfoldr (fmap swap . splitPrimeSuffix) a)
+    & report
+        "L.reverse (unfoldr (fmap swap . splitPrimeSuffix) a)"
+        (L.reverse (unfoldr (fmap swap . splitPrimeSuffix) a))
+
+factorialMonoidLaw_reverse
+    :: (Eq a, Show a, FactorialMonoid a) => a -> Property
+factorialMonoidLaw_reverse a =
+    makeProperty
+        "reverse a == mconcat (L.reverse (factors a))"
+        (reverse a == mconcat (L.reverse (factors a)))
+    & report
+        "reverse a"
+        (reverse a)
+    & report
+        "factors a"
+        (factors a)
+    & report
+        "L.reverse (factors a)"
+        (L.reverse (factors a))
+    & report
+        "mconcat (L.reverse (factors a))"
+        (mconcat (L.reverse (factors a)))
+
+factorialMonoidLaw_primePrefix
+    :: (Eq a, Show a, FactorialMonoid a) => a -> Property
+factorialMonoidLaw_primePrefix a =
+    makeProperty
+        "primePrefix a == maybe mempty fst (splitPrimePrefix a)"
+        (primePrefix a == maybe mempty fst (splitPrimePrefix a))
+    & report
+        "primePrefix a"
+        (primePrefix a)
+    & report
+        "splitPrimePrefix a"
+        (splitPrimePrefix a)
+    & report
+        "maybe mempty fst (splitPrimePrefix a)"
+        (maybe mempty fst (splitPrimePrefix a))
+
+factorialMonoidLaw_primeSuffix
+    :: (Eq a, Show a, FactorialMonoid a) => a -> Property
+factorialMonoidLaw_primeSuffix a =
+    makeProperty
+        "primeSuffix a == maybe mempty snd (splitPrimeSuffix a)"
+        (primeSuffix a == maybe mempty snd (splitPrimeSuffix a))
+    & report
+        "primeSuffix a"
+        (primeSuffix a)
+    & report
+        "splitPrimeSuffix a"
+        (splitPrimeSuffix a)
+    & report
+        "maybe mempty snd (splitPrimeSuffix a)"
+        (maybe mempty snd (splitPrimeSuffix a))
+
+factorialMonoidLaw_inits
+    :: (Eq a, Show a, FactorialMonoid a) => a -> Property
+factorialMonoidLaw_inits a =
+    makeProperty
+        "inits a == fmap mconcat (L.inits (factors a))"
+        (inits a == fmap mconcat (L.inits (factors a)))
+    & report
+        "inits a"
+        (inits a)
+    & report
+        "factors a"
+        (factors a)
+    & report
+        "L.inits (factors a)"
+        (L.inits (factors a))
+    & report
+        "fmap mconcat (L.inits (factors a))"
+        (fmap mconcat (L.inits (factors a)))
+
+factorialMonoidLaw_tails
+    :: (Eq a, Show a, FactorialMonoid a) => a -> Property
+factorialMonoidLaw_tails a =
+    makeProperty
+        "tails a == fmap mconcat (L.tails (factors a))"
+        (tails a == fmap mconcat (L.tails (factors a)))
+    & report
+        "tails a"
+        (tails a)
+    & report
+        "factors a"
+        (factors a)
+    & report
+        "L.tails (factors a)"
+        (L.tails (factors a))
+    & report
+        "fmap mconcat (L.tails (factors a))"
+        (fmap mconcat (L.tails (factors a)))
+
+factorialMonoidLaw_span
+    :: forall a. (Eq a, Show a, FactorialMonoid a)
+    => a
+    -> Property
+factorialMonoidLaw_span a = withShowableFn $ \p ->
+    makeProperty
+        "span p a == bimap mconcat mconcat (L.span p (factors a))"
+        (span p a == bimap mconcat mconcat (L.span p (factors a)))
+    & cover
+        "any p (factors a)"
+        (any p (factors a))
+    & cover
+        "any (not . p) (factors a)"
+        (any (not . p) (factors a))
+    & report
+        "span p a"
+        (span p a)
+    & report
+        "factors a"
+        (factors a)
+    & report
+        "L.span p (factors a)"
+        (L.span p (factors a))
+    & report
+        "bimap mconcat mconcat (L.span p (factors a))"
+        (bimap mconcat mconcat (L.span p (factors a)))
+
+factorialMonoidLaw_split
+    :: forall a. (Eq a, Show a, FactorialMonoid a)
+    => a
+    -> Property
+factorialMonoidLaw_split a = withShowableFn $ \p ->
+    makeProperty
+        "L.all (L.all (not . p) . factors) (split p a)"
+        (L.all (L.all (not . p) . factors) (split p a))
+    & cover
+        "any p (factors a)"
+        (any p (factors a))
+    & cover
+        "any (not . p) (factors a)"
+        (any (not . p) (factors a))
+    & report
+        "split p a"
+        (split p a)
+
+factorialMonoidLaw_split_intersperse
+    :: forall a. (Eq a, Show a, FactorialMonoid a)
+    => a
+    -> Property
+factorialMonoidLaw_split_intersperse a =
+    forAll (elements (factors a)) $ \p ->
+        makeProperty
+            "mconcat (L.intersperse p (split (== p) a)) == a"
+            (mconcat (L.intersperse p (split (== p) a)) == a)
+        & report
+            "split (== p) a"
+            (split (== p) a)
+        & report
+            "L.intersperse p (split (== p) a)"
+            (L.intersperse p (split (== p) a))
+        & report
+            "mconcat (L.intersperse p (split (== p) a))"
+            (mconcat (L.intersperse p (split (== p) a)))
+
+factorialMonoidLaw_splitAt
+    :: forall a. (Eq a, Show a, FactorialMonoid a)
+    => a
+    -> Property
+factorialMonoidLaw_splitAt a =
+    forAll (chooseInt (0, length a)) $ \i ->
+        makeProperty
+            "splitAt i a == bimap mconcat mconcat (L.splitAt i (factors a))"
+            (splitAt i a == bimap mconcat mconcat (L.splitAt i (factors a)))
+        & report
+            "splitAt i a"
+            (splitAt i a)
+        & report
+            "factors a"
+            (factors a)
+        & report
+            "L.splitAt i (factors a)"
+            (L.splitAt i (factors a))
+        & report
+            "bimap mconcat mconcat (L.splitAt i (factors a))"
+            (bimap mconcat mconcat (L.splitAt i (factors a)))
+
+--------------------------------------------------------------------------------
+-- Utilities
+--------------------------------------------------------------------------------
+
+withShowableFn
+    :: forall a b t. (Show a, Show b, Arbitrary b, Testable t)
+    => ((a -> b) -> t)
+    -> Property
+withShowableFn t =
+    forAllShrink (arbitrary @(Fun String b)) shrink $
+        \f -> t ((applyFun f) . show)
diff --git a/src/public/Test/QuickCheck/Classes/Monoid/GCD.hs b/src/public/Test/QuickCheck/Classes/Monoid/GCD.hs
--- a/src/public/Test/QuickCheck/Classes/Monoid/GCD.hs
+++ b/src/public/Test/QuickCheck/Classes/Monoid/GCD.hs
@@ -11,10 +11,12 @@
 --
 module Test.QuickCheck.Classes.Monoid.GCD
     ( gcdMonoidLaws
-    , cancellativeGCDMonoidLaws
     , leftGCDMonoidLaws
     , rightGCDMonoidLaws
     , overlappingGCDMonoidLaws
+    , distributiveGCDMonoidLaws
+    , leftDistributiveGCDMonoidLaws
+    , rightDistributiveGCDMonoidLaws
     )
     where
 
@@ -24,17 +26,20 @@
 import Data.Function
     ( (&) )
 import Data.Maybe
-    ( isJust, isNothing )
+    ( isJust )
 import Data.Monoid.GCD
-    ( GCDMonoid (..)
+    ( DistributiveGCDMonoid
+    , GCDMonoid (..)
+    , LeftDistributiveGCDMonoid
     , LeftGCDMonoid (..)
     , OverlappingGCDMonoid (..)
+    , RightDistributiveGCDMonoid
     , RightGCDMonoid (..)
     )
 import Data.Proxy
     ( Proxy (..) )
 import Data.Semigroup.Cancellative
-    ( Cancellative, LeftReductive (..), Reductive (..), RightReductive (..) )
+    ( LeftReductive (..), Reductive (..), RightReductive (..) )
 import Internal
     ( cover, makeLaw1, makeLaw2, makeLaw3, makeProperty, report, (==>) )
 import Test.QuickCheck
@@ -43,90 +48,6 @@
     ( Laws (..) )
 
 --------------------------------------------------------------------------------
--- CancellativeGCDMonoid
---------------------------------------------------------------------------------
-
--- | 'Laws' for instances of 'Cancellative' and 'GCDMonoid'.
---
--- Includes the following laws:
---
--- @
--- 'gcd' (a '<>' b) (a '<>' c) '==' a '<>' 'gcd' b c
--- @
---
--- @
--- 'gcd' (a '<>' c) (b '<>' c) '==' 'gcd' a b '<>' c
--- @
---
--- Note that the following superclass laws are __not__ included:
---
--- * 'Test.QuickCheck.Classes.Semigroup.Cancellative.cancellativeLaws'
--- * 'Test.QuickCheck.Classes.Monoid.GCD.gcdMonoidLaws'
---
-cancellativeGCDMonoidLaws
-    :: forall a. (Arbitrary a, Show a, Eq a, Cancellative a, GCDMonoid a)
-    => Proxy a
-    -> Laws
-cancellativeGCDMonoidLaws _ = Laws "CancellativeGCDMonoid"
-    [ makeLaw3 @a
-        "cancellativeGCDMonoidLaw_prefix"
-        (cancellativeGCDMonoidLaw_prefix)
-    , makeLaw3 @a
-        "cancellativeGCDMonoidLaw_suffix"
-        (cancellativeGCDMonoidLaw_suffix)
-    ]
-
-cancellativeGCDMonoidLaw_prefix
-    :: (Eq a, Show a, Cancellative a, GCDMonoid a) => a -> a -> a -> Property
-cancellativeGCDMonoidLaw_prefix a b c =
-    makeProperty
-        "gcd (a <> b) (a <> c) == a <> gcd b c"
-        (gcd (a <> b) (a <> c) == a <> gcd b c)
-    & report
-        "a <> b"
-        (a <> b)
-    & report
-        "a <> c"
-        (a <> c)
-    & report
-        "gcd (a <> b) (a <> c)"
-        (gcd (a <> b) (a <> c))
-    & report
-        "gcd b c"
-        (gcd b c)
-    & report
-        "a <> gcd b c"
-        (a <> gcd b c)
-    & cover
-        "a /= mempty && gcd b c /= mempty && a /= gcd b c"
-        (a /= mempty && gcd b c /= mempty && a /= gcd b c)
-
-cancellativeGCDMonoidLaw_suffix
-    :: (Eq a, Show a, Cancellative a, GCDMonoid a) => a -> a -> a -> Property
-cancellativeGCDMonoidLaw_suffix a b c =
-    makeProperty
-        "gcd (a <> c) (b <> c) == gcd a b <> c"
-        (gcd (a <> c) (b <> c) == gcd a b <> c)
-    & report
-        "a <> c"
-        (a <> c)
-    & report
-        "b <> c"
-        (b <> c)
-    & report
-        "gcd (a <> c) (b <> c)"
-        (gcd (a <> c) (b <> c))
-    & report
-        "gcd a b"
-        (gcd a b)
-    & report
-        "gcd a b <> c"
-        (gcd a b <> c)
-    & cover
-        "c /= mempty && gcd a b /= mempty && c /= gcd a b"
-        (c /= mempty && gcd a b /= mempty && c /= gcd a b)
-
---------------------------------------------------------------------------------
 -- GCDMonoid
 --------------------------------------------------------------------------------
 
@@ -182,15 +103,6 @@
 -- 'gcd' ('gcd' a b) c '==' 'gcd' a ('gcd' b c)
 -- @
 --
--- __/Distributivity/__
---
--- @
--- 'gcd' (a '<>' b) (a '<>' c) '==' a '<>' 'gcd' b c
--- @
--- @
--- 'gcd' (a '<>' c) (b '<>' c) '==' 'gcd' a b '<>' c
--- @
---
 -- __/Equivalences/__
 --
 -- @
@@ -238,12 +150,6 @@
     , makeLaw3 @a
         "gcdMonoidLaw_associativity"
         (gcdMonoidLaw_associativity)
-    , makeLaw3 @a
-        "gcdMonoidLaw_distributivity_left"
-        (gcdMonoidLaw_distributivity_left)
-    , makeLaw3 @a
-        "gcdMonoidLaw_distributivity_right"
-        (gcdMonoidLaw_distributivity_right)
     , makeLaw2 @a
         "gcdMonoidLaw_equivalence_commonPrefix"
         (gcdMonoidLaw_equivalence_commonPrefix)
@@ -401,50 +307,6 @@
         "gcd a (gcd b c)"
         (gcd a (gcd b c))
 
-gcdMonoidLaw_distributivity_left
-    :: (Eq a, Show a, GCDMonoid a) => a -> a -> a -> Property
-gcdMonoidLaw_distributivity_left a b c =
-    makeProperty
-        "gcd (a <> b) (a <> c) == a <> gcd b c"
-        (gcd (a <> b) (a <> c) == a <> gcd b c)
-    & report
-        "a <> b"
-        (a <> b)
-    & report
-        "a <> c"
-        (a <> c)
-    & report
-        "gcd (a <> b) (a <> c)"
-        (gcd (a <> b) (a <> c))
-    & report
-        "gcd b c"
-        (gcd b c)
-    & report
-        "a <> gcd b c"
-        (a <> gcd b c)
-
-gcdMonoidLaw_distributivity_right
-    :: (Eq a, Show a, GCDMonoid a) => a -> a -> a -> Property
-gcdMonoidLaw_distributivity_right a b c =
-    makeProperty
-        "gcd (a <> c) (b <> c) == gcd a b <> c"
-        (gcd (a <> c) (b <> c) == gcd a b <> c)
-    & report
-        "a <> c"
-        (a <> c)
-    & report
-        "b <> c"
-        (b <> c)
-    & report
-        "gcd (a <> c) (b <> c)"
-        (gcd (a <> c) (b <> c))
-    & report
-        "gcd a b"
-        (gcd a b)
-    & report
-        "gcd a b <> c"
-        (gcd a b <> c)
-
 gcdMonoidLaw_equivalence_commonPrefix
     :: (Eq a, Show a, GCDMonoid a) => a -> a -> Property
 gcdMonoidLaw_equivalence_commonPrefix a b =
@@ -530,7 +392,7 @@
 -- __/Commutativity/__
 --
 -- @
--- 'commonPrefix' a b == 'commonPrefix' b a
+-- 'commonPrefix' a b '==' 'commonPrefix' b a
 -- @
 --
 -- __/Associativity/__
@@ -541,12 +403,6 @@
 -- 'commonPrefix' a ('commonPrefix' b c)
 -- @
 --
--- __/Distributivity/__
---
--- @
--- 'commonPrefix' (a '<>' b) (a '<>' c) '==' a '<>' 'commonPrefix' b c
--- @
---
 -- __/Equivalences/__
 --
 -- @
@@ -603,9 +459,6 @@
     , makeLaw3 @a
         "leftGCDMonoidLaw_associativity"
         (leftGCDMonoidLaw_associativity)
-    , makeLaw3 @a
-        "leftGCDMonoidLaw_distributivity"
-        (leftGCDMonoidLaw_distributivity)
     , makeLaw2 @a
         "leftGCDMonoidLaw_stripCommonPrefix_commonPrefix"
         (leftGCDMonoidLaw_stripCommonPrefix_commonPrefix)
@@ -784,31 +637,6 @@
         "commonPrefix a (commonPrefix b c)"
         (commonPrefix a (commonPrefix b c))
 
-leftGCDMonoidLaw_distributivity
-    :: (Eq a, Show a, LeftGCDMonoid a) => a -> a -> a -> Property
-leftGCDMonoidLaw_distributivity a b c =
-    makeProperty
-        "commonPrefix (a <> b) (a <> c) == a <> commonPrefix b c"
-        (commonPrefix (a <> b) (a <> c) == a <> commonPrefix b c)
-    & cover
-        "commonPrefix b c /= mempty && a /= mempty"
-        (commonPrefix b c /= mempty && a /= mempty)
-    & report
-        "a <> b"
-        (a <> b)
-    & report
-        "a <> c"
-        (a <> c)
-    & report
-        "commonPrefix (a <> b) (a <> c)"
-        (commonPrefix (a <> b) (a <> c))
-    & report
-        "commonPrefix b c"
-        (commonPrefix b c)
-    & report
-        "a <> commonPrefix b c"
-        (a <> commonPrefix b c)
-
 leftGCDMonoidLaw_stripCommonPrefix_commonPrefix
     :: (Eq a, Show a, LeftGCDMonoid a) => a -> a -> Property
 leftGCDMonoidLaw_stripCommonPrefix_commonPrefix a b =
@@ -897,7 +725,33 @@
 --
 -- Includes the following laws:
 --
+-- __/Reductivity/__
+--
 -- @
+-- 'isJust' ('stripSuffix' ('overlap' a b) a)
+-- @
+-- @
+-- 'isJust' ('stripPrefix' ('overlap' a b) b)
+-- @
+--
+-- __/Idempotence/__
+--
+-- @
+-- 'overlap' a a '==' a
+-- @
+--
+-- __/Identity/__
+--
+-- @
+-- 'overlap' 'mempty' a '==' 'mempty'
+-- @
+-- @
+-- 'overlap' a 'mempty' '==' 'mempty'
+-- @
+--
+-- __/Equivalences/__
+--
+-- @
 -- 'overlap' a b '<>' 'stripPrefixOverlap' a b '==' b
 -- @
 --
@@ -929,6 +783,21 @@
     -> Laws
 overlappingGCDMonoidLaws _ = Laws "OverlappingGCDMonoid"
     [ makeLaw2 @a
+        "overlappingGCDMonoidLaw_reductivity_left"
+        (overlappingGCDMonoidLaw_reductivity_left)
+    , makeLaw2 @a
+        "overlappingGCDMonoidLaw_reductivity_right"
+        (overlappingGCDMonoidLaw_reductivity_right)
+    , makeLaw1 @a
+        "overlappingGCDMonoidLaw_idempotence"
+        (overlappingGCDMonoidLaw_idempotence)
+    , makeLaw1 @a
+        "overlappingGCDMonoidLaw_identity_left"
+        (overlappingGCDMonoidLaw_identity_left)
+    , makeLaw1 @a
+        "overlappingGCDMonoidLaw_identity_right"
+        (overlappingGCDMonoidLaw_identity_right)
+    , makeLaw2 @a
         "overlappingGCDMonoidLaw_overlap_stripPrefixOverlap"
         (overlappingGCDMonoidLaw_overlap_stripPrefixOverlap)
     , makeLaw2 @a
@@ -945,6 +814,80 @@
         (overlappingGCDMonoidLaw_stripOverlap_stripSuffixOverlap)
     ]
 
+overlappingGCDMonoidLaw_reductivity_left
+    :: (Eq a, Show a, OverlappingGCDMonoid a) => a -> a -> Property
+overlappingGCDMonoidLaw_reductivity_left a b =
+    makeProperty
+        "isJust (stripSuffix (overlap a b) a)"
+        (isJust (stripSuffix (overlap a b) a))
+    & cover
+        "overlap a b /= mempty"
+        (overlap a b /= mempty)
+    & cover
+        "stripSuffix (overlap a b) a /= mempty"
+        (stripSuffix (overlap a b) a /= mempty)
+    & report
+        "overlap a b"
+        (overlap a b)
+    & report
+        "stripSuffix (overlap a b) a"
+        (stripSuffix (overlap a b) a)
+
+overlappingGCDMonoidLaw_reductivity_right
+    :: (Eq a, Show a, OverlappingGCDMonoid a) => a -> a -> Property
+overlappingGCDMonoidLaw_reductivity_right a b =
+    makeProperty
+        "isJust (stripPrefix (overlap a b) b)"
+        (isJust (stripPrefix (overlap a b) b))
+    & cover
+        "overlap a b /= mempty"
+        (overlap a b /= mempty)
+    & cover
+        "stripPrefix (overlap a b) b /= mempty"
+        (stripPrefix (overlap a b) b /= mempty)
+    & report
+        "overlap a b"
+        (overlap a b)
+    & report
+        "stripPrefix (overlap a b) b"
+        (stripPrefix (overlap a b) b)
+
+overlappingGCDMonoidLaw_idempotence
+    :: (Eq a, Show a, OverlappingGCDMonoid a) => a -> Property
+overlappingGCDMonoidLaw_idempotence a =
+    makeProperty
+        "overlap a a == a"
+        (overlap a a == a)
+    & report
+        "overlap a a"
+        (overlap a a)
+
+overlappingGCDMonoidLaw_identity_left
+    :: (Eq a, Show a, OverlappingGCDMonoid a) => a -> Property
+overlappingGCDMonoidLaw_identity_left a =
+    makeProperty
+        "overlap mempty a == mempty"
+        (overlap mempty a == mempty)
+    & cover
+        "a /= mempty"
+        (a /= mempty)
+    & report
+        "overlap mempty a"
+        (overlap mempty a)
+
+overlappingGCDMonoidLaw_identity_right
+    :: (Eq a, Show a, OverlappingGCDMonoid a) => a -> Property
+overlappingGCDMonoidLaw_identity_right a =
+    makeProperty
+        "overlap a mempty == mempty"
+        (overlap a mempty == mempty)
+    & cover
+        "a /= mempty"
+        (a /= mempty)
+    & report
+        "overlap a mempty"
+        (overlap a mempty)
+
 overlappingGCDMonoidLaw_overlap_stripPrefixOverlap
     :: (Eq a, Show a, OverlappingGCDMonoid a) => a -> a -> Property
 overlappingGCDMonoidLaw_overlap_stripPrefixOverlap a b =
@@ -1078,7 +1021,7 @@
 -- __/Commutativity/__
 --
 -- @
--- 'commonSuffix' a b == 'commonSuffix' b a
+-- 'commonSuffix' a b '==' 'commonSuffix' b a
 -- @
 --
 -- __/Associativity/__
@@ -1089,12 +1032,6 @@
 -- 'commonSuffix' a ('commonSuffix' b c)
 -- @
 --
--- __/Distributivity/__
---
--- @
--- 'commonSuffix' (a '<>' c) (b '<>' c) '==' 'commonSuffix' a b '<>' c
--- @
---
 -- __/Equivalences/__
 --
 -- @
@@ -1151,9 +1088,6 @@
     , makeLaw3 @a
         "rightGCDMonoidLaw_associativity"
         (rightGCDMonoidLaw_associativity)
-    , makeLaw3 @a
-        "rightGCDMonoidLaw_distributivity"
-        (rightGCDMonoidLaw_distributivity)
     , makeLaw2 @a
         "rightGCDMonoidLaw_stripCommonSuffix_commonSuffix"
         (rightGCDMonoidLaw_stripCommonSuffix_commonSuffix)
@@ -1332,31 +1266,6 @@
         "commonSuffix a (commonSuffix b c)"
         (commonSuffix a (commonSuffix b c))
 
-rightGCDMonoidLaw_distributivity
-    :: (Eq a, Show a, RightGCDMonoid a) => a -> a -> a -> Property
-rightGCDMonoidLaw_distributivity a b c =
-    makeProperty
-        "commonSuffix (a <> c) (b <> c) == commonSuffix a b <> c"
-        (commonSuffix (a <> c) (b <> c) == commonSuffix a b <> c)
-    & cover
-        "commonSuffix a b /= mempty && c /= mempty"
-        (commonSuffix a b /= mempty && c /= mempty)
-    & report
-        "a <> c"
-        (a <> c)
-    & report
-        "b <> c"
-        (b <> c)
-    & report
-        "commonSuffix (a <> c) (b <> c)"
-        (commonSuffix (a <> c) (b <> c))
-    & report
-        "commonSuffix a b"
-        (commonSuffix a b)
-    & report
-        "commonSuffix a b <> c"
-        (commonSuffix a b <> c)
-
 rightGCDMonoidLaw_stripCommonSuffix_commonSuffix
     :: (Eq a, Show a, RightGCDMonoid a) => a -> a -> Property
 rightGCDMonoidLaw_stripCommonSuffix_commonSuffix a b =
@@ -1436,3 +1345,192 @@
     & report
         "stripCommonSuffix a b & λ(_, _, s) -> stripSuffix s b"
         (stripCommonSuffix a b & \(_, _, s) -> stripSuffix s b)
+
+--------------------------------------------------------------------------------
+-- DistributiveGCDMonoid
+--------------------------------------------------------------------------------
+
+-- | 'Laws' for instances of 'DistributiveGCDMonoid'.
+--
+-- Includes the following laws:
+--
+-- __/Left-distributivity/__
+--
+-- @
+-- 'gcd' (a '<>' b) (a '<>' c) '==' a '<>' 'gcd' b c
+-- @
+--
+-- __/Right-distributivity/__
+--
+-- @
+-- 'gcd' (a '<>' c) (b '<>' c) '==' 'gcd' a b '<>' c
+-- @
+--
+-- Note that the following superclass laws are __not__ included:
+--
+-- * 'gcdMonoidLaws'
+-- * 'leftDistributiveGCDMonoidLaws'
+-- * 'rightDistributiveGCDMonoidLaws'
+--
+distributiveGCDMonoidLaws
+    :: forall a. (Arbitrary a, Show a, Eq a, DistributiveGCDMonoid a)
+    => Proxy a
+    -> Laws
+distributiveGCDMonoidLaws _ = Laws "DistributiveGCDMonoid"
+    [ makeLaw3 @a
+        "distributiveGCDMonoidLaw_distributivity_left"
+        (distributiveGCDMonoidLaw_distributivity_left)
+    , makeLaw3 @a
+        "distributiveGCDMonoidLaw_distributivity_right"
+        (distributiveGCDMonoidLaw_distributivity_right)
+    ]
+
+distributiveGCDMonoidLaw_distributivity_left
+    :: (Eq a, Show a, DistributiveGCDMonoid a) => a -> a -> a -> Property
+distributiveGCDMonoidLaw_distributivity_left a b c =
+    makeProperty
+        "gcd (a <> b) (a <> c) == a <> gcd b c"
+        (gcd (a <> b) (a <> c) == a <> gcd b c)
+    & report
+        "a <> b"
+        (a <> b)
+    & report
+        "a <> c"
+        (a <> c)
+    & report
+        "gcd (a <> b) (a <> c)"
+        (gcd (a <> b) (a <> c))
+    & report
+        "gcd b c"
+        (gcd b c)
+    & report
+        "a <> gcd b c"
+        (a <> gcd b c)
+
+distributiveGCDMonoidLaw_distributivity_right
+    :: (Eq a, Show a, DistributiveGCDMonoid a) => a -> a -> a -> Property
+distributiveGCDMonoidLaw_distributivity_right a b c =
+    makeProperty
+        "gcd (a <> c) (b <> c) == gcd a b <> c"
+        (gcd (a <> c) (b <> c) == gcd a b <> c)
+    & report
+        "a <> c"
+        (a <> c)
+    & report
+        "b <> c"
+        (b <> c)
+    & report
+        "gcd (a <> c) (b <> c)"
+        (gcd (a <> c) (b <> c))
+    & report
+        "gcd a b"
+        (gcd a b)
+    & report
+        "gcd a b <> c"
+        (gcd a b <> c)
+
+--------------------------------------------------------------------------------
+-- LeftDistributiveGCDMonoid
+--------------------------------------------------------------------------------
+
+-- | 'Laws' for instances of 'LeftDistributiveGCDMonoid'.
+--
+-- Includes the following law:
+--
+-- __/Left-distributivity/__
+--
+-- @
+-- 'commonPrefix' (a '<>' b) (a '<>' c) '==' a '<>' 'commonPrefix' b c
+-- @
+--
+-- Note that the following superclass laws are __not__ included:
+--
+-- * 'leftGCDMonoidLaws'
+--
+leftDistributiveGCDMonoidLaws
+    :: forall a. (Arbitrary a, Show a, Eq a, LeftDistributiveGCDMonoid a)
+    => Proxy a
+    -> Laws
+leftDistributiveGCDMonoidLaws _ = Laws "LeftDistributiveGCDMonoid"
+    [ makeLaw3 @a
+        "leftDistributiveGCDMonoidLaw_distributivity"
+        (leftDistributiveGCDMonoidLaw_distributivity)
+    ]
+
+leftDistributiveGCDMonoidLaw_distributivity
+    :: (Eq a, Show a, LeftDistributiveGCDMonoid a) => a -> a -> a -> Property
+leftDistributiveGCDMonoidLaw_distributivity a b c =
+    makeProperty
+        "commonPrefix (a <> b) (a <> c) == a <> commonPrefix b c"
+        (commonPrefix (a <> b) (a <> c) == a <> commonPrefix b c)
+    & cover
+        "commonPrefix b c /= mempty && a /= mempty"
+        (commonPrefix b c /= mempty && a /= mempty)
+    & report
+        "a <> b"
+        (a <> b)
+    & report
+        "a <> c"
+        (a <> c)
+    & report
+        "commonPrefix (a <> b) (a <> c)"
+        (commonPrefix (a <> b) (a <> c))
+    & report
+        "commonPrefix b c"
+        (commonPrefix b c)
+    & report
+        "a <> commonPrefix b c"
+        (a <> commonPrefix b c)
+
+--------------------------------------------------------------------------------
+-- RightDistributiveGCDMonoid
+--------------------------------------------------------------------------------
+
+-- | 'Laws' for instances of 'RightDistributiveGCDMonoid'.
+--
+-- Includes the following law:
+--
+-- __/Right-distributivity/__
+--
+-- @
+-- 'commonSuffix' (a '<>' c) (b '<>' c) '==' 'commonSuffix' a b '<>' c
+-- @
+--
+-- Note that the following superclass laws are __not__ included:
+--
+-- * 'rightGCDMonoidLaws'
+--
+rightDistributiveGCDMonoidLaws
+    :: forall a. (Arbitrary a, Show a, Eq a, RightDistributiveGCDMonoid a)
+    => Proxy a
+    -> Laws
+rightDistributiveGCDMonoidLaws _ = Laws "RightDistributiveGCDMonoid"
+    [ makeLaw3 @a
+        "rightDistributiveGCDMonoidLaw_distributivity"
+        (rightDistributiveGCDMonoidLaw_distributivity)
+    ]
+
+rightDistributiveGCDMonoidLaw_distributivity
+    :: (Eq a, Show a, RightDistributiveGCDMonoid a) => a -> a -> a -> Property
+rightDistributiveGCDMonoidLaw_distributivity a b c =
+    makeProperty
+        "commonSuffix (a <> c) (b <> c) == commonSuffix a b <> c"
+        (commonSuffix (a <> c) (b <> c) == commonSuffix a b <> c)
+    & cover
+        "commonSuffix a b /= mempty && c /= mempty"
+        (commonSuffix a b /= mempty && c /= mempty)
+    & report
+        "a <> c"
+        (a <> c)
+    & report
+        "b <> c"
+        (b <> c)
+    & report
+        "commonSuffix (a <> c) (b <> c)"
+        (commonSuffix (a <> c) (b <> c))
+    & report
+        "commonSuffix a b"
+        (commonSuffix a b)
+    & report
+        "commonSuffix a b <> c"
+        (commonSuffix a b <> c)
diff --git a/src/public/Test/QuickCheck/Classes/Monoid/LCM.hs b/src/public/Test/QuickCheck/Classes/Monoid/LCM.hs
--- a/src/public/Test/QuickCheck/Classes/Monoid/LCM.hs
+++ b/src/public/Test/QuickCheck/Classes/Monoid/LCM.hs
@@ -11,6 +11,7 @@
 --
 module Test.QuickCheck.Classes.Monoid.LCM
     ( lcmMonoidLaws
+    , distributiveLCMMonoidLaws
     )
     where
 
@@ -22,19 +23,13 @@
 import Data.Maybe
     ( isJust )
 import Data.Monoid.GCD
-    ( GCDMonoid (..), OverlappingGCDMonoid (..) )
+    ( GCDMonoid (..) )
 import Data.Monoid.LCM
-    ( LCMMonoid (..) )
-import Data.Monoid.Monus
-    ( Monus (..) )
+    ( DistributiveLCMMonoid, LCMMonoid (..) )
 import Data.Proxy
     ( Proxy (..) )
 import Data.Semigroup.Cancellative
-    ( Cancellative (..)
-    , LeftReductive (..)
-    , Reductive (..)
-    , RightReductive (..)
-    )
+    ( Reductive (..) )
 import Internal
     ( cover, makeLaw1, makeLaw2, makeLaw3, makeProperty, report, (==>) )
 import Test.QuickCheck
@@ -98,21 +93,6 @@
 -- 'lcm' ('lcm' a b) c '==' 'lcm' a ('lcm' b c)
 -- @
 --
--- __/Distributivity/__
---
--- @
--- 'lcm' (a '<>' b) (a '<>' c) '==' a '<>' 'lcm' b c
--- @
--- @
--- 'lcm' (a '<>' c) (b '<>' c) '==' 'lcm' a b '<>' c
--- @
--- @
--- 'lcm' a ('gcd' b c) '==' 'gcd' ('lcm' a b) ('lcm' a c)
--- @
--- @
--- 'gcd' a ('lcm' b c) '==' 'lcm' ('gcd' a b) ('gcd' a c)
--- @
---
 -- __/Absorption/__
 --
 -- @
@@ -155,18 +135,6 @@
     , makeLaw3 @a
         "lcmMonoidLaw_associativity"
         (lcmMonoidLaw_associativity)
-    , makeLaw3 @a
-        "lcmMonoidLaw_distributivity_left"
-        (lcmMonoidLaw_distributivity_left)
-    , makeLaw3 @a
-        "lcmMonoidLaw_distributivity_right"
-        (lcmMonoidLaw_distributivity_right)
-    , makeLaw3 @a
-        "lcmMonoidLaw_distributivity_gcd_lcm"
-        (lcmMonoidLaw_distributivity_gcd_lcm)
-    , makeLaw3 @a
-        "lcmMonoidLaw_distributivity_lcm_gcd"
-        (lcmMonoidLaw_distributivity_lcm_gcd)
     , makeLaw2 @a
         "lcmMonoidLaw_absorption_gcd_lcm"
         (lcmMonoidLaw_absorption_gcd_lcm)
@@ -321,10 +289,102 @@
         "lcm a (lcm b c)"
         (lcm a (lcm b c))
 
-lcmMonoidLaw_distributivity_left
-    :: (Eq a, Show a, LCMMonoid a) => a -> a -> a -> Property
-lcmMonoidLaw_distributivity_left a b c =
+lcmMonoidLaw_absorption_gcd_lcm
+    :: (Eq a, Show a, LCMMonoid a) => a -> a -> Property
+lcmMonoidLaw_absorption_gcd_lcm a b =
     makeProperty
+        "lcm a (gcd a b) == a"
+        (lcm a (gcd a b) == a)
+    & cover
+        "gcd a b == mempty"
+        (gcd a b == mempty)
+    & cover
+        "gcd a b /= mempty"
+        (gcd a b /= mempty)
+    & report
+        "gcd a b"
+        (gcd a b)
+    & report
+        "lcm a (gcd a b)"
+        (lcm a (gcd a b))
+
+lcmMonoidLaw_absorption_lcm_gcd
+    :: (Eq a, Show a, LCMMonoid a) => a -> a -> Property
+lcmMonoidLaw_absorption_lcm_gcd a b =
+    makeProperty
+        "gcd a (lcm a b) == a"
+        (gcd a (lcm a b) == a)
+    & cover
+        "gcd a b == mempty"
+        (gcd a b == mempty)
+    & cover
+        "gcd a b /= mempty"
+        (gcd a b /= mempty)
+    & report
+        "lcm a b"
+        (lcm a b)
+    & report
+        "gcd a (lcm a b)"
+        (gcd a (lcm a b))
+
+--------------------------------------------------------------------------------
+-- DistributiveLCMMonoid
+--------------------------------------------------------------------------------
+
+-- | 'Laws' for instances of 'DistributiveLCMMonoid'.
+--
+-- Includes the following laws:
+--
+-- __/Left-distributivity/__
+--
+-- @
+-- 'lcm' (a '<>' b) (a '<>' c) '==' a '<>' 'lcm' b c
+-- @
+--
+-- __/Right-distributivity/__
+--
+-- @
+-- 'lcm' (a '<>' c) (b '<>' c) '==' 'lcm' a b '<>' c
+-- @
+--
+-- __/Lattice distributivity/__
+--
+-- @
+-- 'lcm' a ('gcd' b c) '==' 'gcd' ('lcm' a b) ('lcm' a c)
+-- @
+--
+-- @
+-- 'gcd' a ('lcm' b c) '==' 'lcm' ('gcd' a b) ('gcd' a c)
+-- @
+--
+-- Note that the following superclass laws are __not__ included:
+--
+-- * 'Test.QuickCheck.Classes.Monoid.GCD.distributiveGCDMonoidLaws'
+-- * 'lcmMonoidLaws'
+--
+distributiveLCMMonoidLaws
+    :: forall a. (Arbitrary a, Show a, Eq a, DistributiveLCMMonoid a)
+    => Proxy a
+    -> Laws
+distributiveLCMMonoidLaws _ = Laws "DistributiveLCMMonoid"
+    [ makeLaw3 @a
+        "distributiveLCMMonoidLaw_distributivity_left"
+        (distributiveLCMMonoidLaw_distributivity_left)
+    , makeLaw3 @a
+        "distributiveLCMMonoidLaw_distributivity_right"
+        (distributiveLCMMonoidLaw_distributivity_right)
+    , makeLaw3 @a
+        "distributiveLCMMonoidLaw_distributivity_gcd_lcm"
+        (distributiveLCMMonoidLaw_distributivity_gcd_lcm)
+    , makeLaw3 @a
+        "distributiveLCMMonoidLaw_distributivity_lcm_gcd"
+        (distributiveLCMMonoidLaw_distributivity_lcm_gcd)
+    ]
+
+distributiveLCMMonoidLaw_distributivity_left
+    :: (Eq a, Show a, DistributiveLCMMonoid a) => a -> a -> a -> Property
+distributiveLCMMonoidLaw_distributivity_left a b c =
+    makeProperty
         "lcm (a <> b) (a <> c) == a <> lcm b c"
         (lcm (a <> b) (a <> c) == a <> lcm b c)
     & report
@@ -343,9 +403,9 @@
         "a <> lcm b c"
         (a <> lcm b c)
 
-lcmMonoidLaw_distributivity_right
-    :: (Eq a, Show a, LCMMonoid a) => a -> a -> a -> Property
-lcmMonoidLaw_distributivity_right a b c =
+distributiveLCMMonoidLaw_distributivity_right
+    :: (Eq a, Show a, DistributiveLCMMonoid a) => a -> a -> a -> Property
+distributiveLCMMonoidLaw_distributivity_right a b c =
     makeProperty
         "lcm (a <> c) (b <> c) == lcm a b <> c"
         (lcm (a <> c) (b <> c) == lcm a b <> c)
@@ -365,54 +425,16 @@
         "lcm a b <> c"
         (lcm a b <> c)
 
-lcmMonoidLaw_distributivity_gcd_lcm
-    :: (Eq a, Show a, LCMMonoid a) => a -> a -> a -> Property
-lcmMonoidLaw_distributivity_gcd_lcm a b c =
+distributiveLCMMonoidLaw_distributivity_gcd_lcm
+    :: (Eq a, Show a, DistributiveLCMMonoid a) => a -> a -> a -> Property
+distributiveLCMMonoidLaw_distributivity_gcd_lcm a b c =
     makeProperty
         "lcm a (gcd b c) == gcd (lcm a b) (lcm a c)"
         (lcm a (gcd b c) == gcd (lcm a b) (lcm a c))
 
-lcmMonoidLaw_distributivity_lcm_gcd
-    :: (Eq a, Show a, LCMMonoid a) => a -> a -> a -> Property
-lcmMonoidLaw_distributivity_lcm_gcd a b c =
+distributiveLCMMonoidLaw_distributivity_lcm_gcd
+    :: (Eq a, Show a, DistributiveLCMMonoid a) => a -> a -> a -> Property
+distributiveLCMMonoidLaw_distributivity_lcm_gcd a b c =
     makeProperty
         "gcd a (lcm b c) == lcm (gcd a b) (gcd a c)"
         (gcd a (lcm b c) == lcm (gcd a b) (gcd a c))
-
-lcmMonoidLaw_absorption_gcd_lcm
-    :: (Eq a, Show a, LCMMonoid a) => a -> a -> Property
-lcmMonoidLaw_absorption_gcd_lcm a b =
-    makeProperty
-        "lcm a (gcd a b) == a"
-        (lcm a (gcd a b) == a)
-    & cover
-        "gcd a b == mempty"
-        (gcd a b == mempty)
-    & cover
-        "gcd a b /= mempty"
-        (gcd a b /= mempty)
-    & report
-        "gcd a b"
-        (gcd a b)
-    & report
-        "lcm a (gcd a b)"
-        (lcm a (gcd a b))
-
-lcmMonoidLaw_absorption_lcm_gcd
-    :: (Eq a, Show a, LCMMonoid a) => a -> a -> Property
-lcmMonoidLaw_absorption_lcm_gcd a b =
-    makeProperty
-        "gcd a (lcm a b) == a"
-        (gcd a (lcm a b) == a)
-    & cover
-        "gcd a b == mempty"
-        (gcd a b == mempty)
-    & cover
-        "gcd a b /= mempty"
-        (gcd a b /= mempty)
-    & report
-        "lcm a b"
-        (lcm a b)
-    & report
-        "gcd a (lcm a b)"
-        (gcd a (lcm a b))
diff --git a/src/public/Test/QuickCheck/Classes/Semigroup/Factorial.hs b/src/public/Test/QuickCheck/Classes/Semigroup/Factorial.hs
new file mode 100644
--- /dev/null
+++ b/src/public/Test/QuickCheck/Classes/Semigroup/Factorial.hs
@@ -0,0 +1,423 @@
+{- HLINT ignore "Avoid lambda" -}
+{- HLINT ignore "Redundant bracket" -}
+{- HLINT ignore "Use camelCase" -}
+{- HLINT ignore "Use const" -}
+{- HLINT ignore "Use null" -}
+
+-- |
+-- Copyright: © 2022–2023 Jonathan Knowles
+-- License: Apache-2.0
+--
+-- This module provides 'Laws' definitions for classes exported by
+-- "Data.Semigroup.Factorial".
+--
+module Test.QuickCheck.Classes.Semigroup.Factorial
+    ( factorialLaws
+    , stableFactorialLaws
+    )
+    where
+
+import Prelude hiding
+    ( foldl, foldr, length, reverse )
+
+import Data.Function
+    ( (&) )
+import Data.List.NonEmpty
+    ( nonEmpty )
+import Data.Proxy
+    ( Proxy )
+import Data.Semigroup
+    ( Semigroup (sconcat) )
+import Data.Semigroup.Factorial
+    ( Factorial
+    , StableFactorial
+    , factors
+    , foldl
+    , foldl'
+    , foldr
+    , length
+    , primePrefix
+    , primeSuffix
+    , reverse
+    )
+import Internal
+    ( cover, makeLaw1, makeLaw2, makeProperty, report )
+import Test.QuickCheck
+    ( Arbitrary, Gen, Property, elements, forAllBlind )
+import Test.QuickCheck.Classes
+    ( Laws (Laws) )
+
+import qualified Data.List as L
+
+--------------------------------------------------------------------------------
+-- Factorial
+--------------------------------------------------------------------------------
+
+-- | 'Laws' for instances of 'Factorial'.
+--
+-- Includes the following laws:
+--
+-- @
+-- 'length' a '==' "Data.List".'Data.List.length' ('factors' a)
+-- @
+--
+-- @
+-- 'maybe' a 'sconcat' ('nonEmpty'   \ \ \     \ $ 'factors' a) '==' \       \ a
+-- 'maybe' a 'sconcat' ('nonEmpty' $ 'L.reverse' $ 'factors' a) '==' 'reverse' a
+-- @
+--
+-- @
+-- 'all' (\\f -> 'factors' f '==' [f]) ('factors' a)
+-- @
+--
+-- @
+-- 'primePrefix' a '==' 'foldr' (\\x _ -> x) a a
+-- 'primeSuffix' a '==' 'foldl' (\\_ x -> x) a a
+-- @
+--
+-- @
+-- 'foldl'  f x a '==' "Data.List".'Data.List.foldl'  f x ('factors' a)
+-- 'foldl'' f x a '==' "Data.List".'Data.List.foldl'' f x ('factors' a)
+-- 'foldr'  f x a '==' "Data.List".'Data.List.foldr'  f x ('factors' a)
+-- @
+--
+-- Note that the following superclass laws are __not__ included:
+--
+-- * 'Test.QuickCheck.Classes.semigroupLaws'
+--
+factorialLaws
+    :: forall a. (Arbitrary a, Show a, Eq a, Factorial a)
+    => Proxy a
+    -> Laws
+factorialLaws _ = Laws "Factorial"
+    [ makeLaw1 @a
+        "factorialLaw_coverage"
+        (factorialLaw_coverage)
+    , makeLaw1 @a
+        "factorialLaw_length_factors"
+        (factorialLaw_length_factors)
+    , makeLaw1 @a
+        "factorialLaw_maybe_sconcat_nonEmpty_factors"
+        (factorialLaw_maybe_sconcat_nonEmpty_factors)
+    , makeLaw1 @a
+        "factorialLaw_maybe_sconcat_nonEmpty_factors_reverse"
+        (factorialLaw_maybe_sconcat_nonEmpty_factors_reverse)
+    , makeLaw1 @a
+        "factorialLaw_all_factors_prime"
+        (factorialLaw_all_factors_prime)
+    , makeLaw1 @a
+        "factorialLaw_primePrefix_foldr"
+        (factorialLaw_primePrefix_foldr)
+    , makeLaw1 @a
+        "factorialLaw_primeSuffix_foldl"
+        (factorialLaw_primeSuffix_foldl)
+    , makeLaw2 @a
+        "factorialLaw_factors_foldl"
+        (factorialLaw_factors_foldl)
+    , makeLaw2 @a
+        "factorialLaw_factors_foldl'"
+        (factorialLaw_factors_foldl')
+    , makeLaw2 @a
+        "factorialLaw_factors_foldr"
+        (factorialLaw_factors_foldr)
+    ]
+
+factorialLaw_coverage
+    :: (Eq a, Show a, Factorial a) => a -> Property
+factorialLaw_coverage a =
+    makeProperty
+        "True"
+        (True)
+    & cover
+        "length a == 0"
+        (length a == 0)
+    & cover
+        "length a == 1"
+        (length a == 1)
+    & cover
+        "length a >= 2"
+        (length a >= 2)
+
+factorialLaw_length_factors
+    :: (Eq a, Show a, Factorial a) => a -> Property
+factorialLaw_length_factors a =
+    makeProperty
+        "length a == L.length (factors a)"
+        (length a == L.length (factors a))
+    & report
+        "length a"
+        (length a)
+    & report
+        "L.length (factors a)"
+        (L.length (factors a))
+
+factorialLaw_maybe_sconcat_nonEmpty_factors
+    :: (Eq a, Show a, Factorial a) => a -> Property
+factorialLaw_maybe_sconcat_nonEmpty_factors a =
+    makeProperty
+        "maybe a sconcat (nonEmpty (factors a)) == a"
+        (maybe a sconcat (nonEmpty (factors a)) == a)
+    & report
+        "factors a"
+        (factors a)
+    & report
+        "nonEmpty (factors a)"
+        (nonEmpty (factors a))
+    & report
+        "fmap sconcat (nonEmpty (factors a))"
+        (fmap sconcat (nonEmpty (factors a)))
+
+factorialLaw_maybe_sconcat_nonEmpty_factors_reverse
+    :: (Eq a, Show a, Factorial a) => a -> Property
+factorialLaw_maybe_sconcat_nonEmpty_factors_reverse a =
+    makeProperty
+        "maybe a sconcat (nonEmpty (L.reverse (factors a))) == reverse a"
+        (maybe a sconcat (nonEmpty (L.reverse (factors a))) == reverse a)
+    & report
+        "factors a"
+        (factors a)
+    & report
+        "L.reverse (factors a)"
+        (L.reverse (factors a))
+    & report
+        "nonEmpty (L.reverse (factors a))"
+        (nonEmpty (L.reverse (factors a)))
+    & report
+        "maybe a sconcat (nonEmpty (L.reverse (factors a)))"
+        (maybe a sconcat (nonEmpty (L.reverse (factors a))))
+    & report
+        "reverse a"
+        (reverse a)
+
+factorialLaw_all_factors_prime
+    :: (Eq a, Show a, Factorial a) => a -> Property
+factorialLaw_all_factors_prime a =
+    makeProperty
+        "all (λf -> factors f == [f]) (factors a)"
+        (all (\f -> factors f == [f]) (factors a))
+    & report
+        "factors a"
+        (factors a)
+    & report
+        "factors <$> factors a"
+        (factors <$> factors a)
+
+factorialLaw_primePrefix_foldr
+    :: (Eq a, Show a, Factorial a) => a -> Property
+factorialLaw_primePrefix_foldr a =
+    makeProperty
+        "primePrefix a == foldr (λx _ -> x) a a"
+        (primePrefix a == foldr (\x _ -> x) a a)
+    & report
+        "factors a"
+        (factors a)
+    & report
+        "primePrefix a"
+        (primePrefix a)
+    & report
+        "foldr (λx _ -> x) a a"
+        (foldr (\x _ -> x) a a)
+
+factorialLaw_primeSuffix_foldl
+    :: (Eq a, Show a, Factorial a) => a -> Property
+factorialLaw_primeSuffix_foldl a =
+    makeProperty
+        "primeSuffix a == foldl (λ_ x -> x) a a"
+        (primeSuffix a == foldl (\_ x -> x) a a)
+    & report
+        "factors a"
+        (factors a)
+    & report
+        "primeSuffix a"
+        (primeSuffix a)
+    & report
+        "foldl (λ_ x -> x) a a"
+        (foldl (\_ x -> x) a a)
+
+factorialLaw_factors_foldl
+    :: (Eq a, Show a, Factorial a) => a -> a -> Property
+factorialLaw_factors_foldl x a =
+    forAllBlind genAccumulatorFn $ \(fDefinition, f) ->
+        makeProperty
+            "foldl f x a == L.foldl f x (factors a)"
+            (foldl f x a == L.foldl f x (factors a))
+        & report
+            "f"
+            (fDefinition)
+        & report
+            "foldl f x a"
+            (foldl f x a)
+        & report
+            "L.foldl f x (factors a)"
+            (L.foldl f x (factors a))
+
+factorialLaw_factors_foldl'
+    :: (Eq a, Show a, Factorial a) => a -> a -> Property
+factorialLaw_factors_foldl' x a =
+    forAllBlind genAccumulatorFn $ \(fDefinition, f) ->
+        makeProperty
+            "foldl' f x a == L.foldl' f x (factors a)"
+            (foldl' f x a == L.foldl' f x (factors a))
+        & report
+            "f"
+            (fDefinition)
+        & report
+            "foldl' f x a"
+            (foldl' f x a)
+        & report
+            "L.foldl' f x (factors a)"
+            (L.foldl' f x (factors a))
+
+factorialLaw_factors_foldr
+    :: (Eq a, Show a, Factorial a) => a -> a -> Property
+factorialLaw_factors_foldr x a =
+    forAllBlind genAccumulatorFn $ \(fDefinition, f) ->
+        makeProperty
+            "foldr f x a == L.foldr f x (factors a)"
+            (foldr f x a == L.foldr f x (factors a))
+        & report
+            "f"
+            (fDefinition)
+        & report
+            "foldr f x a"
+            (foldr f x a)
+        & report
+            "L.foldr f x (factors a)"
+            (L.foldr f x (factors a))
+
+--------------------------------------------------------------------------------
+-- StableFactorial
+--------------------------------------------------------------------------------
+
+-- | 'Laws' for instances of 'StableFactorial'.
+--
+-- Includes the following laws:
+--
+-- @
+-- 'factors' (a '<>' b) '==' 'factors' a '<>' 'factors' b
+-- @
+--
+-- @
+-- 'factors' ('reverse' a) '==' "Data.List".'L.reverse' ('factors' a)
+-- @
+--
+-- @
+-- 'primePrefix' a '==' 'primeSuffix' ('reverse' a)
+-- 'primeSuffix' a '==' 'primePrefix' ('reverse' a)
+-- @
+--
+-- Note that the following superclass laws are __not__ included:
+--
+-- * 'factorialLaws'
+--
+stableFactorialLaws
+    :: forall a. (Arbitrary a, Show a, Eq a, StableFactorial a)
+    => Proxy a
+    -> Laws
+stableFactorialLaws _ = Laws "StableFactorial"
+    [ makeLaw2 @a
+        "stableFactorialLaw_factors_mappend"
+        (stableFactorialLaw_factors_mappend)
+    , makeLaw1 @a
+        "stableFactorialLaw_factors_reverse"
+        (stableFactorialLaw_factors_reverse)
+    , makeLaw1 @a
+        "stableFactorialLaw_primePrefix_primeSuffix_reverse"
+        (stableFactorialLaw_primePrefix_primeSuffix_reverse)
+    , makeLaw1 @a
+        "stableFactorialLaw_primeSuffix_primePrefix_reverse"
+        (stableFactorialLaw_primeSuffix_primePrefix_reverse)
+    ]
+
+stableFactorialLaw_factors_mappend
+    :: (Eq a, Show a, StableFactorial a) => a -> a -> Property
+stableFactorialLaw_factors_mappend a b =
+    makeProperty
+        "factors (a <> b) == factors a <> factors b"
+        (factors (a <> b) == factors a <> factors b)
+    & report
+        "a <> b"
+        (a <> b)
+    & report
+        "factors a"
+        (factors a)
+    & report
+        "factors b"
+        (factors b)
+    & report
+        "factors (a <> b)"
+        (factors (a <> b))
+    & report
+        "factors a <> factors b"
+        (factors a <> factors b)
+
+stableFactorialLaw_factors_reverse
+    :: (Eq a, Show a, StableFactorial a) => a -> Property
+stableFactorialLaw_factors_reverse a =
+    makeProperty
+        "factors (reverse a) == L.reverse (factors a)"
+        (factors (reverse a) == L.reverse (factors a))
+    & report
+        "reverse a"
+        (reverse a)
+    & report
+        "factors (reverse a)"
+        (factors (reverse a))
+    & report
+        "factors a"
+        (factors a)
+    & report
+        "L.reverse (factors a)"
+        (L.reverse (factors a))
+
+stableFactorialLaw_primePrefix_primeSuffix_reverse
+    :: (Eq a, Show a, StableFactorial a) => a -> Property
+stableFactorialLaw_primePrefix_primeSuffix_reverse a =
+    makeProperty
+        "primePrefix a == primeSuffix (reverse a)"
+        (primePrefix a == primeSuffix (reverse a))
+    & report
+        "primePrefix a"
+        (primePrefix a)
+    & report
+        "reverse a"
+        (reverse a)
+    & report
+        "primeSuffix (reverse a)"
+        (primeSuffix (reverse a))
+
+stableFactorialLaw_primeSuffix_primePrefix_reverse
+    :: (Eq a, Show a, StableFactorial a) => a -> Property
+stableFactorialLaw_primeSuffix_primePrefix_reverse a =
+    makeProperty
+        "primeSuffix a == primePrefix (reverse a)"
+        (primeSuffix a == primePrefix (reverse a))
+    & report
+        "primeSuffix a"
+        (primeSuffix a)
+    & report
+        "reverse a"
+        (reverse a)
+    & report
+        "primePrefix (reverse a)"
+        (primePrefix (reverse a))
+
+--------------------------------------------------------------------------------
+-- Utilities
+--------------------------------------------------------------------------------
+
+genAccumulatorFn :: Semigroup a => Gen (String, a -> a -> a)
+genAccumulatorFn = elements
+    [ ( "λa _ -> a"
+      , (\a _ -> a)
+      )
+    , ( "λ_ b -> b"
+      , (\_ b -> b)
+      )
+    , ( "λa b -> a <> b"
+      , (\a b -> a <> b)
+      )
+    , ( "λa b -> b <> a"
+      , (\a b -> b <> a)
+      )
+    ]
diff --git a/src/test/ClassSpec.hs b/src/test/ClassSpec.hs
--- a/src/test/ClassSpec.hs
+++ b/src/test/ClassSpec.hs
@@ -13,7 +13,7 @@
 import Data.Map.Strict
     ( Map )
 import Data.Monoid
-    ( Product (..), Sum (..) )
+    ( Dual (..), Product (..), Sum (..) )
 import Data.Monoid.GCD
     ( GCDMonoid, LeftGCDMonoid, OverlappingGCDMonoid, RightGCDMonoid )
 import Data.Monoid.Monus
@@ -47,24 +47,22 @@
 import Test.Hspec.Laws
     ( testLawsMany )
 import Test.QuickCheck
-    ( Arbitrary (..)
-    , Confidence
-    , Property
-    , arbitrarySizedIntegral
-    , scale
-    , shrinkMap
-    )
+    ( Arbitrary (..), Confidence, Property, scale, shrinkMap )
 import Test.QuickCheck.Classes
     ( Laws (..) )
+import Test.QuickCheck.Classes.Monoid.Factorial
+    ( factorialMonoidLaws )
 import Test.QuickCheck.Classes.Monoid.GCD
-    ( cancellativeGCDMonoidLaws
+    ( distributiveGCDMonoidLaws
     , gcdMonoidLaws
+    , leftDistributiveGCDMonoidLaws
     , leftGCDMonoidLaws
     , overlappingGCDMonoidLaws
+    , rightDistributiveGCDMonoidLaws
     , rightGCDMonoidLaws
     )
 import Test.QuickCheck.Classes.Monoid.LCM
-    ( lcmMonoidLaws )
+    ( distributiveLCMMonoidLaws, lcmMonoidLaws )
 import Test.QuickCheck.Classes.Monoid.Monus
     ( monusLaws )
 import Test.QuickCheck.Classes.Monoid.Null
@@ -78,6 +76,8 @@
     , rightCancellativeLaws
     , rightReductiveLaws
     )
+import Test.QuickCheck.Classes.Semigroup.Factorial
+    ( factorialLaws, stableFactorialLaws )
 import Test.QuickCheck.Instances.ByteString
     ()
 import Test.QuickCheck.Instances.Natural
@@ -92,12 +92,16 @@
 spec :: Spec
 spec = do
     testLawsMany @() $ fmap disableCoverageCheck <$>
-        [ cancellativeGCDMonoidLaws
-        , cancellativeLaws
+        [ cancellativeLaws
         , commutativeLaws
+        , distributiveGCDMonoidLaws
+        , distributiveLCMMonoidLaws
+        , factorialLaws
+        , factorialMonoidLaws
         , gcdMonoidLaws
         , lcmMonoidLaws
         , leftCancellativeLaws
+        , leftDistributiveGCDMonoidLaws
         , leftGCDMonoidLaws
         , leftReductiveLaws
         , monoidNullLaws
@@ -106,83 +110,215 @@
         , positiveMonoidLaws
         , reductiveLaws
         , rightCancellativeLaws
+        , rightDistributiveGCDMonoidLaws
         , rightGCDMonoidLaws
         , rightReductiveLaws
+        , stableFactorialLaws
         ]
     testLawsMany @ByteString
-        [ leftCancellativeLaws
+        [ factorialLaws
+        , factorialMonoidLaws
+        , leftCancellativeLaws
+        , leftDistributiveGCDMonoidLaws
         , leftGCDMonoidLaws
         , leftReductiveLaws
         , monoidNullLaws
         , overlappingGCDMonoidLaws
         , positiveMonoidLaws
         , rightCancellativeLaws
+        , rightDistributiveGCDMonoidLaws
         , rightGCDMonoidLaws
         , rightReductiveLaws
+        , stableFactorialLaws
         ]
+    testLawsMany @(Dual ByteString)
+        [ factorialLaws
+        , factorialMonoidLaws
+        , leftCancellativeLaws
+        , leftDistributiveGCDMonoidLaws
+        , leftGCDMonoidLaws
+        , leftReductiveLaws
+        , monoidNullLaws
+        , overlappingGCDMonoidLaws
+        , positiveMonoidLaws
+        , rightCancellativeLaws
+        , rightDistributiveGCDMonoidLaws
+        , rightGCDMonoidLaws
+        , rightReductiveLaws
+        , stableFactorialLaws
+        ]
     testLawsMany @Text
-        [ leftCancellativeLaws
+        [ factorialLaws
+        , factorialMonoidLaws
+        , leftCancellativeLaws
+        , leftDistributiveGCDMonoidLaws
         , leftGCDMonoidLaws
         , leftReductiveLaws
         , monoidNullLaws
         , overlappingGCDMonoidLaws
         , positiveMonoidLaws
         , rightCancellativeLaws
+        , rightDistributiveGCDMonoidLaws
         , rightGCDMonoidLaws
         , rightReductiveLaws
+        , stableFactorialLaws
         ]
+    testLawsMany @(Dual Text)
+        [ factorialLaws
+        , factorialMonoidLaws
+        , leftCancellativeLaws
+        , leftDistributiveGCDMonoidLaws
+        , leftGCDMonoidLaws
+        , leftReductiveLaws
+        , monoidNullLaws
+        , overlappingGCDMonoidLaws
+        , positiveMonoidLaws
+        , rightCancellativeLaws
+        , rightDistributiveGCDMonoidLaws
+        , rightGCDMonoidLaws
+        , rightReductiveLaws
+        , stableFactorialLaws
+        ]
     testLawsMany @[SmallInt]
-        [ leftCancellativeLaws
+        [ factorialLaws
+        , factorialMonoidLaws
+        , leftCancellativeLaws
+        , leftDistributiveGCDMonoidLaws
         , leftGCDMonoidLaws
         , leftReductiveLaws
         , monoidNullLaws
         , overlappingGCDMonoidLaws
         , positiveMonoidLaws
         , rightCancellativeLaws
+        , rightDistributiveGCDMonoidLaws
         , rightGCDMonoidLaws
         , rightReductiveLaws
+        , stableFactorialLaws
         ]
+    testLawsMany @(Dual [SmallInt])
+        [ factorialLaws
+        , factorialMonoidLaws
+        , leftCancellativeLaws
+        , leftDistributiveGCDMonoidLaws
+        , leftGCDMonoidLaws
+        , leftReductiveLaws
+        , monoidNullLaws
+        , overlappingGCDMonoidLaws
+        , positiveMonoidLaws
+        , rightCancellativeLaws
+        , rightDistributiveGCDMonoidLaws
+        , rightGCDMonoidLaws
+        , rightReductiveLaws
+        , stableFactorialLaws
+        ]
     testLawsMany @(Seq SmallInt)
-        [ leftCancellativeLaws
+        [ factorialLaws
+        , factorialMonoidLaws
+        , leftCancellativeLaws
+        , leftDistributiveGCDMonoidLaws
         , leftGCDMonoidLaws
         , leftReductiveLaws
         , monoidNullLaws
         , overlappingGCDMonoidLaws
         , positiveMonoidLaws
         , rightCancellativeLaws
+        , rightDistributiveGCDMonoidLaws
         , rightGCDMonoidLaws
         , rightReductiveLaws
+        , stableFactorialLaws
         ]
+    testLawsMany @(Dual (Seq SmallInt))
+        [ factorialLaws
+        , factorialMonoidLaws
+        , leftCancellativeLaws
+        , leftDistributiveGCDMonoidLaws
+        , leftGCDMonoidLaws
+        , leftReductiveLaws
+        , monoidNullLaws
+        , overlappingGCDMonoidLaws
+        , positiveMonoidLaws
+        , rightCancellativeLaws
+        , rightDistributiveGCDMonoidLaws
+        , rightGCDMonoidLaws
+        , rightReductiveLaws
+        , stableFactorialLaws
+        ]
+    testLawsMany @(Vector SmallInt)
+        [ factorialLaws
+        , factorialMonoidLaws
+        , leftCancellativeLaws
+        , leftDistributiveGCDMonoidLaws
+        , leftGCDMonoidLaws
+        , leftReductiveLaws
+        , monoidNullLaws
+        , overlappingGCDMonoidLaws
+        , positiveMonoidLaws
+        , rightCancellativeLaws
+        , rightDistributiveGCDMonoidLaws
+        , rightGCDMonoidLaws
+        , rightReductiveLaws
+        , stableFactorialLaws
+        ]
+    testLawsMany @(Dual (Vector SmallInt))
+        [ factorialLaws
+        , factorialMonoidLaws
+        , leftCancellativeLaws
+        , leftDistributiveGCDMonoidLaws
+        , leftGCDMonoidLaws
+        , leftReductiveLaws
+        , monoidNullLaws
+        , overlappingGCDMonoidLaws
+        , positiveMonoidLaws
+        , rightCancellativeLaws
+        , rightDistributiveGCDMonoidLaws
+        , rightGCDMonoidLaws
+        , rightReductiveLaws
+        , stableFactorialLaws
+        ]
     testLawsMany @(Set SmallInt)
         [ commutativeLaws
+        , distributiveGCDMonoidLaws
+        , distributiveLCMMonoidLaws
+        , factorialLaws
+        , factorialMonoidLaws
         , gcdMonoidLaws
+        , lcmMonoidLaws
+        , leftDistributiveGCDMonoidLaws
         , leftGCDMonoidLaws
         , leftReductiveLaws
-        , lcmMonoidLaws
         , monoidNullLaws
         , monusLaws
         , overlappingGCDMonoidLaws
         , positiveMonoidLaws
         , reductiveLaws
+        , rightDistributiveGCDMonoidLaws
         , rightGCDMonoidLaws
         , rightReductiveLaws
         ]
     testLawsMany @(Set Natural)
         [ commutativeLaws
+        , distributiveGCDMonoidLaws
+        , distributiveLCMMonoidLaws
+        , factorialLaws
+        , factorialMonoidLaws
         , gcdMonoidLaws
+        , lcmMonoidLaws
+        , leftDistributiveGCDMonoidLaws
         , leftGCDMonoidLaws
         , leftReductiveLaws
-        , lcmMonoidLaws
         , monoidNullLaws
         , monusLaws
         , overlappingGCDMonoidLaws
         , positiveMonoidLaws
         , reductiveLaws
+        , rightDistributiveGCDMonoidLaws
         , rightGCDMonoidLaws
         , rightReductiveLaws
         ]
     testLawsMany @(Product SmallInt)
         [ commutativeLaws
+        , factorialLaws
+        , factorialMonoidLaws
         , leftReductiveLaws
         , monoidNullLaws
         , reductiveLaws
@@ -190,8 +326,13 @@
         ]
     testLawsMany @(Product Natural)
         [ commutativeLaws
+        , distributiveGCDMonoidLaws
+        , distributiveLCMMonoidLaws
+        , factorialLaws
+        , factorialMonoidLaws
         , gcdMonoidLaws
         , lcmMonoidLaws
+        , leftDistributiveGCDMonoidLaws
         , leftGCDMonoidLaws
         , leftReductiveLaws
         , monoidNullLaws
@@ -199,12 +340,15 @@
         , overlappingGCDMonoidLaws
         , positiveMonoidLaws
         , reductiveLaws
+        , rightDistributiveGCDMonoidLaws
         , rightGCDMonoidLaws
         , rightReductiveLaws
         ]
     testLawsMany @(Sum SmallInt)
         [ cancellativeLaws
         , commutativeLaws
+        , factorialLaws
+        , factorialMonoidLaws
         , leftCancellativeLaws
         , leftReductiveLaws
         , monoidNullLaws
@@ -213,12 +357,16 @@
         , rightReductiveLaws
         ]
     testLawsMany @(Sum Natural)
-        [ cancellativeGCDMonoidLaws
-        , cancellativeLaws
+        [ cancellativeLaws
         , commutativeLaws
+        , distributiveGCDMonoidLaws
+        , distributiveLCMMonoidLaws
+        , factorialLaws
+        , factorialMonoidLaws
         , gcdMonoidLaws
         , lcmMonoidLaws
         , leftCancellativeLaws
+        , leftDistributiveGCDMonoidLaws
         , leftGCDMonoidLaws
         , leftReductiveLaws
         , monoidNullLaws
@@ -227,11 +375,15 @@
         , positiveMonoidLaws
         , reductiveLaws
         , rightCancellativeLaws
+        , rightDistributiveGCDMonoidLaws
         , rightGCDMonoidLaws
         , rightReductiveLaws
+        , stableFactorialLaws
         ]
     testLawsMany @(IntMap SmallInt)
-        [ leftGCDMonoidLaws
+        [ factorialLaws
+        , factorialMonoidLaws
+        , leftGCDMonoidLaws
         , leftReductiveLaws
         , monoidNullLaws
         , overlappingGCDMonoidLaws
@@ -239,7 +391,9 @@
         , rightReductiveLaws
         ]
     testLawsMany @(IntMap Natural)
-        [ leftGCDMonoidLaws
+        [ factorialLaws
+        , factorialMonoidLaws
+        , leftGCDMonoidLaws
         , leftReductiveLaws
         , monoidNullLaws
         , overlappingGCDMonoidLaws
@@ -247,7 +401,9 @@
         , rightReductiveLaws
         ]
     testLawsMany @(Map Int SmallInt)
-        [ leftGCDMonoidLaws
+        [ factorialLaws
+        , factorialMonoidLaws
+        , leftGCDMonoidLaws
         , leftReductiveLaws
         , monoidNullLaws
         , overlappingGCDMonoidLaws
@@ -255,7 +411,9 @@
         , rightReductiveLaws
         ]
     testLawsMany @(Map Int Natural)
-        [ leftGCDMonoidLaws
+        [ factorialLaws
+        , factorialMonoidLaws
+        , leftGCDMonoidLaws
         , leftReductiveLaws
         , monoidNullLaws
         , overlappingGCDMonoidLaws
@@ -264,6 +422,8 @@
         ]
     testLawsMany @(Maybe ()) $ fmap disableCoverageCheck <$>
         [ commutativeLaws
+        , factorialLaws
+        , factorialMonoidLaws
         , leftGCDMonoidLaws
         , leftReductiveLaws
         , monoidNullLaws
@@ -276,6 +436,8 @@
         ]
     testLawsMany @(Maybe (Product SmallInt))
         [ commutativeLaws
+        , factorialLaws
+        , factorialMonoidLaws
         , leftReductiveLaws
         , monoidNullLaws
         , positiveMonoidLaws
@@ -284,6 +446,8 @@
         ]
     testLawsMany @(Maybe (Product Natural))
         [ commutativeLaws
+        , factorialLaws
+        , factorialMonoidLaws
         , leftGCDMonoidLaws
         , leftReductiveLaws
         , monoidNullLaws
@@ -296,6 +460,8 @@
         ]
     testLawsMany @(Maybe (Sum SmallInt))
         [ commutativeLaws
+        , factorialLaws
+        , factorialMonoidLaws
         , leftReductiveLaws
         , monoidNullLaws
         , positiveMonoidLaws
@@ -304,6 +470,8 @@
         ]
     testLawsMany @(Maybe (Sum Natural))
         [ commutativeLaws
+        , factorialLaws
+        , factorialMonoidLaws
         , leftGCDMonoidLaws
         , leftReductiveLaws
         , monoidNullLaws
@@ -314,17 +482,6 @@
         , rightGCDMonoidLaws
         , rightReductiveLaws
         ]
-    testLawsMany @(Vector SmallInt)
-        [ leftCancellativeLaws
-        , leftGCDMonoidLaws
-        , leftReductiveLaws
-        , monoidNullLaws
-        , overlappingGCDMonoidLaws
-        , positiveMonoidLaws
-        , rightCancellativeLaws
-        , rightGCDMonoidLaws
-        , rightReductiveLaws
-        ]
 
 --------------------------------------------------------------------------------
 -- Notes
@@ -332,12 +489,16 @@
 
 {- All laws tested in this module:
 
-        [ cancellativeGCDMonoidLaws
-        , cancellativeLaws
+        [ cancellativeLaws
         , commutativeLaws
+        , distributiveGCDMonoidLaws
+        , distributiveLCMMonoidLaws
+        , factorialLaws
+        , factorialMonoidLaws
         , gcdMonoidLaws
         , lcmMonoidLaws
         , leftCancellativeLaws
+        , leftDistributiveGCDMonoidLaws
         , leftGCDMonoidLaws
         , leftReductiveLaws
         , monoidNullLaws
@@ -346,8 +507,10 @@
         , positiveMonoidLaws
         , reductiveLaws
         , rightCancellativeLaws
+        , rightDistributiveGCDMonoidLaws
         , rightGCDMonoidLaws
         , rightReductiveLaws
+        , stableFactorialLaws
         ]
 -}
 
