diff --git a/README.md b/README.md
--- a/README.md
+++ b/README.md
@@ -1,1 +1,94 @@
 # quickcheck-classes
+
+This library provides sets of properties that should hold for common typeclasses,
+along with three (3) simple functions that you can use to test them.
+
+### `lawsCheck`:
+
+A convenience function for testing properties in GHCi.
+For example, at GHCi:
+
+```bash
+>>> lawsCheck (monoidLaws (Proxy :: Proxy Ordering))
+Monoid: Associative +++ OK, passed 100 tests.
+Monoid: Left Identity +++ OK, passed 100 tests.
+Monoid: Right Identity +++ OK, passed 100 tests.
+```
+
+Assuming that the `Arbitrary` instance for `Ordering` is good, we now
+have confidence that the `Monoid` instance for `Ordering` satisfies
+the monoid laws.
+
+### `lawsCheckMany`:
+
+A convenience function for checking multiple typeclass instances
+of multiple types. Consider the following Haskell source file:
+
+```haskell
+import Data.Proxy (Proxy(..))
+import Data.Map (Map)
+import Data.Set (Set)
+
+-- A 'Proxy' for 'Set' 'Int'. 
+setInt :: Proxy (Set Int)
+setInt = Proxy
+
+-- A 'Proxy' for 'Map' 'Int' 'Int'.
+mapInt :: Proxy (Map Int Int)
+mapInt = Proxy
+
+myLaws :: Proxy a -> [Laws]
+myLaws p = [eqLaws p, monoidLaws p]
+
+namedTests :: [(String, [Laws])]
+namedTests =
+  [ ("Set Int", myLaws setInt)
+  , ("Map Int Int", myLaws mapInt)
+  ]
+```
+
+Now, in GHCi:
+
+```bash
+>>> lawsCheckMany namedTests
+
+Testing properties for common typeclasses
+-------------
+-- Set Int --
+-------------
+
+Eq: Transitive +++ OK, passed 100 tests.
+Eq: Symmetric +++ OK, passed 100 tests.
+Eq: Reflexive +++ OK, passed 100 tests.
+Monoid: Associative +++ OK, passed 100 tests.
+Monoid: Left Identity +++ OK, passed 100 tests.
+Monoid: Right Identity +++ OK, passed 100 tests.
+Monoid: Concatenation +++ OK, passed 100 tests.
+
+-----------------
+-- Map Int Int --
+-----------------
+
+Eq: Transitive +++ OK, passed 100 tests.
+Eq: Symmetric +++ OK, passed 100 tests.
+Eq: Reflexive +++ OK, passed 100 tests.
+Monoid: Associative +++ OK, passed 100 tests.
+Monoid: Left Identity +++ OK, passed 100 tests.
+Monoid: Right Identity +++ OK, passed 100 tests.
+Monoid: Concatenation +++ OK, passed 100 tests.
+
+```
+
+### `specialisedLawsCheckMany`
+
+A convenience function that allows one to check many typeclass
+instances of the same type.
+
+For example, in GHCi:
+
+```bash
+>>> specialisedLawsCheckMany (Proxy :: Proxy Word) [jsonLaws, showReadLaws]
+ToJSON/FromJSON: Encoding Equals Value +++ OK, passed 100 tests.
+ToJSON/FromJSON: Partial Isomorphism +++ OK, passed 100 tests.
+Show/Read: Partial Isomorphism +++ OK, passed 100 tests.
+```
diff --git a/changelog.md b/changelog.md
--- a/changelog.md
+++ b/changelog.md
@@ -4,6 +4,15 @@
 The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
 and this project adheres to the [Haskell Package Versioning Policy](https://pvp.haskell.org/).
 
+## [0.4.11] - 2018-05-14
+### Added
+- Greatly improved documentation
+- `specialisedLawsCheckMany` function, a shorter way for the user
+  to use `lawsCheckMany` on a single type.
+
+### Change
+- Some internal names, making it more clear what it is that they do.
+
 ## [0.4.10] - 2018-05-03
 ### Added
 - Property tests for `mconcat`, `sconcat`, and `stimes`. It isn't
diff --git a/quickcheck-classes.cabal b/quickcheck-classes.cabal
--- a/quickcheck-classes.cabal
+++ b/quickcheck-classes.cabal
@@ -1,8 +1,8 @@
 name: quickcheck-classes
-version: 0.4.10
+version: 0.4.11
 synopsis: QuickCheck common typeclasses
 description:
-  This library provides quickcheck properties to ensure
+  This library provides QuickCheck properties to ensure
   that typeclass instances adhere to the set of laws that
   they are supposed to. There are other libraries that do
   similar things, such as `genvalidity-hspec` and `checkers`.
@@ -36,6 +36,13 @@
   default: True
   manual: True
 
+flag semirings
+  description:
+    You can disable the use of the `semirings` package using `-f-semirings`.
+    .
+    This may be useful for accelerating builds in sandboxes for expert users.
+    default: True
+    manual: True
 
 library
   hs-source-dirs: src
@@ -61,6 +68,7 @@
     Test.QuickCheck.Classes.Ord
     Test.QuickCheck.Classes.Prim
     Test.QuickCheck.Classes.Semigroup
+    Test.QuickCheck.Classes.Semiring 
     Test.QuickCheck.Classes.ShowRead
     Test.QuickCheck.Classes.Storable
     Test.QuickCheck.Classes.Traversable
@@ -77,6 +85,8 @@
     build-depends: aeson
   if flag(semigroupoids)
     build-depends: semigroupoids 
+  if flag(semirings)
+    build-depends: semirings >= 0.1.3
   default-language: Haskell2010
 
 test-suite test
diff --git a/src/Test/QuickCheck/Classes.hs b/src/Test/QuickCheck/Classes.hs
--- a/src/Test/QuickCheck/Classes.hs
+++ b/src/Test/QuickCheck/Classes.hs
@@ -1,27 +1,16 @@
 {-# LANGUAGE CPP #-}
+{-# LANGUAGE KindSignatures #-}
 
 {-# OPTIONS_GHC -Wall #-}
 
-{-|
-This library provides sets of properties that should hold for common typeclasses.
-All of these take a 'Proxy' argument that is used to nail down the type for which
-the typeclass dictionaries should be tested. For example, at GHCi:
->>> lawsCheck (monoidLaws (Proxy :: Proxy Ordering))
-Monoid: Associative +++ OK, passed 100 tests.
-Monoid: Left Identity +++ OK, passed 100 tests.
-Monoid: Right Identity +++ OK, passed 100 tests.
-Assuming that the 'Arbitrary' instance for 'Ordering' is good, we now
-have confidence that the 'Monoid' instance for 'Ordering' satisfies
-the monoid laws. We can check multiple typeclasses with:
->>> foldMap (lawsCheck . ($ (Proxy :: Proxy Word))) [jsonLaws,showReadLaws]
-ToJSON/FromJSON: Encoding Equals Value +++ OK, passed 100 tests.
-ToJSON/FromJSON: Partial Isomorphism +++ OK, passed 100 tests.
-Show/Read: Partial Isomorphism +++ OK, passed 100 tests.
+{-| This library provides sets of properties that should hold for common
+    typeclasses.
 -}
 module Test.QuickCheck.Classes
   ( -- * Running 
     lawsCheck
   , lawsCheckMany
+  , specialisedLawsCheckMany 
     -- * Properties
     -- ** Ground types
 #if MIN_VERSION_base(4,7,0)
@@ -61,6 +50,8 @@
 #endif
     -- * Types
   , Laws(..)
+  , Proxy1(..)
+  , Proxy2(..)
   ) where
 
 --
@@ -110,30 +101,105 @@
 --
 import Test.QuickCheck
 import Test.QuickCheck.Classes.Common (foldMapA, Laws(..))
+import Data.Foldable
 import Data.Monoid (Monoid(..))
+import Data.Proxy (Proxy(..))
 import Data.Semigroup (Semigroup)
+import qualified Data.List as List
 import qualified Data.Semigroup as SG
 
 -- | A convenience function for testing properties in GHCi.
---   See the test suite of this library for an example of how to
---   integrate multiple properties into larger test suite.
+-- For example, at GHCi:
+--
+-- >>> lawsCheck (monoidLaws (Proxy :: Proxy Ordering))
+-- Monoid: Associative +++ OK, passed 100 tests.
+-- Monoid: Left Identity +++ OK, passed 100 tests.
+-- Monoid: Right Identity +++ OK, passed 100 tests.
+--
+-- Assuming that the 'Arbitrary' instance for 'Ordering' is good, we now
+-- have confidence that the 'Monoid' instance for 'Ordering' satisfies
+-- the monoid laws.
 lawsCheck :: Laws -> IO ()
 lawsCheck (Laws className properties) = do
   flip foldMapA properties $ \(name,p) -> do
     putStr (className ++ ": " ++ name ++ " ")
     quickCheck p
 
+-- | A convenience function that allows one to check many typeclass
+-- instances of the same type.
+--
+-- >>> specialisedLawsCheckMany (Proxy :: Proxy Word) [jsonLaws, showReadLaws]
+-- ToJSON/FromJSON: Encoding Equals Value +++ OK, passed 100 tests.
+-- ToJSON/FromJSON: Partial Isomorphism +++ OK, passed 100 tests.
+-- Show/Read: Partial Isomorphism +++ OK, passed 100 tests.
+specialisedLawsCheckMany :: Proxy a -> [Proxy a -> Laws] -> IO ()
+specialisedLawsCheckMany p ls = foldMap (lawsCheck . ($ p)) ls
+
 -- | A convenience function for checking multiple typeclass instances
---   of multiple types.
+--   of multiple types. Consider the following Haskell source file:
+--
+-- @
+-- import Data.Proxy (Proxy(..))
+-- import Data.Map (Map)
+-- import Data.Set (Set)
+--
+-- -- A 'Proxy' for 'Set' 'Int'. 
+-- setInt :: Proxy (Set Int)
+-- setInt = Proxy
+-- 
+-- -- A 'Proxy' for 'Map' 'Int' 'Int'.
+-- mapInt :: Proxy (Map Int Int)
+-- mapInt = Proxy
+-- 
+-- myLaws :: Proxy a -> [Laws]
+-- myLaws p = [eqLaws p, monoidLaws p]
+--
+-- namedTests :: [(String, [Laws])]
+-- namedTests =
+--   [ ("Set Int", myLaws setInt)
+--   , ("Map Int Int", myLaws mapInt)
+--   ]
+-- @
+--   
+-- Now, in GHCi:
+--
+-- >>> lawsCheckMany namedTests
+--
+-- @
+-- Testing properties for common typeclasses
+-- -------------
+-- -- Set Int --
+-- -------------
+-- 
+-- Eq: Transitive +++ OK, passed 100 tests.
+-- Eq: Symmetric +++ OK, passed 100 tests.
+-- Eq: Reflexive +++ OK, passed 100 tests.
+-- Monoid: Associative +++ OK, passed 100 tests.
+-- Monoid: Left Identity +++ OK, passed 100 tests.
+-- Monoid: Right Identity +++ OK, passed 100 tests.
+-- Monoid: Concatenation +++ OK, passed 100 tests.
+-- 
+-- -----------------
+-- -- Map Int Int --
+-- -----------------
+-- 
+-- Eq: Transitive +++ OK, passed 100 tests.
+-- Eq: Symmetric +++ OK, passed 100 tests.
+-- Eq: Reflexive +++ OK, passed 100 tests.
+-- Monoid: Associative +++ OK, passed 100 tests.
+-- Monoid: Left Identity +++ OK, passed 100 tests.
+-- Monoid: Right Identity +++ OK, passed 100 tests.
+-- Monoid: Concatenation +++ OK, passed 100 tests.
+-- @
 lawsCheckMany ::
      [(String,[Laws])] -- ^ Element is type name paired with typeclass laws
   -> IO ()
 lawsCheckMany xs = do
   putStrLn "Testing properties for common typeclasses"
   r <- flip foldMapA xs $ \(typeName,laws) -> do
-    putStrLn $ "------------"
-    putStrLn $ "-- " ++ typeName
-    putStrLn $ "------------"
+    putStrLn $ List.replicate (length typeName + 6) '-'
+    putStrLn $ "-- " ++ typeName ++ " --"
+    putStrLn $ List.replicate (length typeName + 6) '-'
     flip foldMapA laws $ \(Laws typeClassName properties) -> do
       flip foldMapA properties $ \(name,p) -> do
         putStr (typeClassName ++ ": " ++ name ++ " ")
@@ -155,3 +221,12 @@
 instance Monoid Status where
   mempty = Good
   mappend = (SG.<>)
+
+-- | In older versions of GHC, Proxy is not poly-kinded,
+--   so we provide Proxy1.
+data Proxy1 (f :: * -> *) = Proxy1
+
+-- | In older versions of GHC, Proxy is not poly-kinded,
+--   so we provide Proxy2.
+data Proxy2 (f :: * -> * -> *) = Proxy2
+
diff --git a/src/Test/QuickCheck/Classes/Applicative.hs b/src/Test/QuickCheck/Classes/Applicative.hs
--- a/src/Test/QuickCheck/Classes/Applicative.hs
+++ b/src/Test/QuickCheck/Classes/Applicative.hs
@@ -52,24 +52,24 @@
 applicativeIdentity _ = property $ \(Apply (a :: f Integer)) -> eq1 (pure id <*> a) a
 
 applicativeComposition :: forall proxy f. (Applicative f, Eq1 f, Show1 f, Arbitrary1 f) => proxy f -> Property
-applicativeComposition _ = property $ \(Apply (u' :: f Equation)) (Apply (v' :: f Equation)) (Apply (w :: f Integer)) ->
-  let u = fmap runEquation u'
-      v = fmap runEquation v'
+applicativeComposition _ = property $ \(Apply (u' :: f QuadraticEquation)) (Apply (v' :: f QuadraticEquation)) (Apply (w :: f Integer)) ->
+  let u = fmap runQuadraticEquation u'
+      v = fmap runQuadraticEquation v'
    in eq1 (pure (.) <*> u <*> v <*> w) (u <*> (v <*> w))
 
 applicativeHomomorphism :: forall proxy f. (Applicative f, Eq1 f, Show1 f) => proxy f -> Property
-applicativeHomomorphism _ = property $ \(e :: Equation) (a :: Integer) ->
-  let f = runEquation e
+applicativeHomomorphism _ = property $ \(e :: QuadraticEquation) (a :: Integer) ->
+  let f = runQuadraticEquation e
    in eq1 (pure f <*> pure a) (pure (f a) :: f Integer)
 
 applicativeInterchange :: forall proxy f. (Applicative f, Eq1 f, Show1 f, Arbitrary1 f) => proxy f -> Property
-applicativeInterchange _ = property $ \(Apply (u' :: f Equation)) (y :: Integer) ->
-  let u = fmap runEquation u'
+applicativeInterchange _ = property $ \(Apply (u' :: f QuadraticEquation)) (y :: Integer) ->
+  let u = fmap runQuadraticEquation u'
    in eq1 (u <*> pure y) (pure ($ y) <*> u)
 
 applicativeLiftA2_1 :: forall proxy f. (Applicative f, Eq1 f, Show1 f, Arbitrary1 f) => proxy f -> Property
-applicativeLiftA2_1 _ = property $ \(Apply (f' :: f Equation)) (Apply (x :: f Integer)) ->
-  let f = fmap runEquation f'
+applicativeLiftA2_1 _ = property $ \(Apply (f' :: f QuadraticEquation)) (Apply (x :: f Integer)) ->
+  let f = fmap runQuadraticEquation f'
    in eq1 (liftA2 id f x) (f <*> x)
 
 #endif
diff --git a/src/Test/QuickCheck/Classes/Bits.hs b/src/Test/QuickCheck/Classes/Bits.hs
--- a/src/Test/QuickCheck/Classes/Bits.hs
+++ b/src/Test/QuickCheck/Classes/Bits.hs
@@ -133,10 +133,10 @@
 bitsClearZero :: forall a. (Bits a, Arbitrary a, Show a) => Proxy a -> Property
 bitsClearZero _ = myForAllShrink False (const True)
   (\(n :: a) -> ["n = " ++ show n])
-  "complement (complement n)"
-  (\n -> complement (complement n))
+  "clearBit zeroBits n"
+  (\n -> clearBit n zeroBits)
   "n"
-  (\n -> n)
+  (\_ -> zeroBits)
 
 bitsSetZero :: forall a. (FiniteBits a, Arbitrary a, Show a) => Proxy a -> Property
 bitsSetZero _ = myForAllShrink True (const True)
diff --git a/src/Test/QuickCheck/Classes/Common.hs b/src/Test/QuickCheck/Classes/Common.hs
--- a/src/Test/QuickCheck/Classes/Common.hs
+++ b/src/Test/QuickCheck/Classes/Common.hs
@@ -21,8 +21,8 @@
 #if MIN_VERSION_base(4,9,0) || MIN_VERSION_transformers(0,4,0)
   , LinearEquationM(..)
 #endif
-  , Equation(..)
-  , EquationTwo(..)
+  , QuadraticEquation(..)
+  , LinearEquationTwo(..)
 #if MIN_VERSION_base(4,9,0) || MIN_VERSION_transformers(0,4,0)
   , nestedEq1
   , propNestedEq1
@@ -45,8 +45,8 @@
 #if MIN_VERSION_base(4,8,0) || MIN_VERSION_transformers(0,5,0)
   , runLinearEquationM
 #endif
-  , runEquation
-  , runEquationTwo
+  , runQuadraticEquation
+  , runLinearEquationTwo
   ) where
 
 import Control.Applicative
@@ -353,44 +353,49 @@
      in map (\(x,y) -> LinearEquation (abs x) (abs y)) xs
 
 -- this is a quadratic equation
-data Equation = Equation Integer Integer Integer
+data QuadraticEquation = QuadraticEquation
+  { _quadraticEquationQuadratic :: Integer
+  , _quadraticEquationLinear :: Integer
+  , _quadraticEquationConstant :: Integer
+  }
   deriving (Eq)
 
 -- This show instance is does not actually provide a
 -- way to create an equation. Instead, it makes it look
 -- like a lambda.
-instance Show Equation where
-  show (Equation a b c) = "\\x -> " ++ show a ++ " * x ^ 2 + " ++ show b ++ " * x + " ++ show c
+instance Show QuadraticEquation where
+  show (QuadraticEquation a b c) = "\\x -> " ++ show a ++ " * x ^ 2 + " ++ show b ++ " * x + " ++ show c
 
-instance Arbitrary Equation where
+instance Arbitrary QuadraticEquation where
   arbitrary = do
     (a,b,c) <- arbitrary
-    return (Equation (abs a) (abs b) (abs c))
-  shrink (Equation a b c) =
+    return (QuadraticEquation (abs a) (abs b) (abs c))
+  shrink (QuadraticEquation a b c) =
     let xs = shrink (a,b,c)
-     in map (\(x,y,z) -> Equation (abs x) (abs y) (abs z)) xs
+     in map (\(x,y,z) -> QuadraticEquation (abs x) (abs y) (abs z)) xs
 
-runEquation :: Equation -> Integer -> Integer
-runEquation (Equation a b c) x = a * x ^ (2 :: Integer) + b * x + c
+runQuadraticEquation :: QuadraticEquation -> Integer -> Integer
+runQuadraticEquation (QuadraticEquation a b c) x = a * x ^ (2 :: Integer) + b * x + c
 
--- linear equation of two variables
-data EquationTwo = EquationTwo Integer Integer
+data LinearEquationTwo = LinearEquationTwo
+  { _linearEquationTwoX :: Integer
+  , _linearEquationTwoY :: Integer
+  }
   deriving (Eq)
 
 -- This show instance does not actually provide a
--- way to create an EquationTwo. Instead, it makes it look
+-- way to create a LinearEquationTwo. Instead, it makes it look
 -- like a lambda that takes two variables.
-instance Show EquationTwo where
-  show (EquationTwo a b) = "\\x y -> " ++ show a ++ " * x + " ++ show b ++ " * y"
+instance Show LinearEquationTwo where
+  show (LinearEquationTwo a b) = "\\x y -> " ++ show a ++ " * x + " ++ show b ++ " * y"
 
-instance Arbitrary EquationTwo where
+instance Arbitrary LinearEquationTwo where
   arbitrary = do
     (a,b) <- arbitrary
-    return (EquationTwo (abs a) (abs b))
-  shrink (EquationTwo a b) =
+    return (LinearEquationTwo (abs a) (abs b))
+  shrink (LinearEquationTwo a b) =
     let xs = shrink (a,b)
-     in map (\(x,y) -> EquationTwo (abs x) (abs y)) xs
-
-runEquationTwo :: EquationTwo -> Integer -> Integer -> Integer
-runEquationTwo (EquationTwo a b) x y = a * x + b * y
+     in map (\(x,y) -> LinearEquationTwo (abs x) (abs y)) xs
 
+runLinearEquationTwo :: LinearEquationTwo -> Integer -> Integer -> Integer
+runLinearEquationTwo (LinearEquationTwo a b) x y = a * x + b * y
diff --git a/src/Test/QuickCheck/Classes/Foldable.hs b/src/Test/QuickCheck/Classes/Foldable.hs
--- a/src/Test/QuickCheck/Classes/Foldable.hs
+++ b/src/Test/QuickCheck/Classes/Foldable.hs
@@ -67,28 +67,28 @@
 foldableLawsInternal p = Laws "Foldable"
   [ (,) "fold" $ property $ \(Apply (a :: f (SG.Sum Integer))) ->
       F.fold a == F.foldMap id a
-  , (,) "foldMap" $ property $ \(Apply (a :: f Integer)) (e :: Equation) ->
-      let f = SG.Sum . runEquation e
+  , (,) "foldMap" $ property $ \(Apply (a :: f Integer)) (e :: QuadraticEquation) ->
+      let f = SG.Sum . runQuadraticEquation e
        in F.foldMap f a == F.foldr (mappend . f) mempty a
-  , (,) "foldr" $ property $ \(e :: EquationTwo) (z :: Integer) (Apply (t :: f Integer)) ->
-      let f = runEquationTwo e
+  , (,) "foldr" $ property $ \(e :: LinearEquationTwo) (z :: Integer) (Apply (t :: f Integer)) ->
+      let f = runLinearEquationTwo e
        in F.foldr f z t == SG.appEndo (foldMap (SG.Endo . f) t) z
   , (,) "foldr'" (foldableFoldr' p)
-  , (,) "foldl" $ property $ \(e :: EquationTwo) (z :: Integer) (Apply (t :: f Integer)) ->
-      let f = runEquationTwo e
+  , (,) "foldl" $ property $ \(e :: LinearEquationTwo) (z :: Integer) (Apply (t :: f Integer)) ->
+      let f = runLinearEquationTwo e
        in F.foldl f z t == SG.appEndo (SG.getDual (F.foldMap (SG.Dual . SG.Endo . flip f) t)) z
   , (,) "foldl'" (foldableFoldl' p)
-  , (,) "foldl1" $ property $ \(e :: EquationTwo) (Apply (t :: f Integer)) ->
+  , (,) "foldl1" $ property $ \(e :: LinearEquationTwo) (Apply (t :: f Integer)) ->
       case compatToList t of
         [] -> True
         x : xs ->
-          let f = runEquationTwo e
+          let f = runLinearEquationTwo e
            in F.foldl1 f t == F.foldl f x xs
-  , (,) "foldr1" $ property $ \(e :: EquationTwo) (Apply (t :: f Integer)) ->
+  , (,) "foldr1" $ property $ \(e :: LinearEquationTwo) (Apply (t :: f Integer)) ->
       case unsnoc (compatToList t) of
         Nothing -> True
         Just (xs,x) ->
-          let f = runEquationTwo e
+          let f = runLinearEquationTwo e
            in F.foldr1 f t == F.foldr f x xs
   , (,) "toList" $ property $ \(Apply (t :: f Integer)) ->
       eq1 (F.toList t) (F.foldr (:) [] t)
diff --git a/src/Test/QuickCheck/Classes/Monad.hs b/src/Test/QuickCheck/Classes/Monad.hs
--- a/src/Test/QuickCheck/Classes/Monad.hs
+++ b/src/Test/QuickCheck/Classes/Monad.hs
@@ -68,8 +68,8 @@
   eq1 (return x) (pure x :: f Integer)
 
 monadAp :: forall proxy f. (Monad f, Applicative f, Eq1 f, Show1 f, Arbitrary1 f) => proxy f -> Property
-monadAp _ = property $ \(Apply (f' :: f Equation)) (Apply (x :: f Integer)) ->
-  let f = fmap runEquation f'
+monadAp _ = property $ \(Apply (f' :: f QuadraticEquation)) (Apply (x :: f Integer)) ->
+  let f = fmap runQuadraticEquation f'
    in eq1 (ap f x) (f <*> x)
 
 #endif
diff --git a/src/Test/QuickCheck/Classes/Monoid.hs b/src/Test/QuickCheck/Classes/Monoid.hs
--- a/src/Test/QuickCheck/Classes/Monoid.hs
+++ b/src/Test/QuickCheck/Classes/Monoid.hs
@@ -32,7 +32,7 @@
   , ("Concatenation", monoidConcatenation p)
   ]
 
--- | Tests everything from 'monoidProps' plus the following:
+-- | Tests everything from 'monoidLaws' plus the following:
 --
 -- [/Commutative/]
 --   @mappend a b ≡ mappend b a@
diff --git a/src/Test/QuickCheck/Classes/Semiring.hs b/src/Test/QuickCheck/Classes/Semiring.hs
new file mode 100644
--- /dev/null
+++ b/src/Test/QuickCheck/Classes/Semiring.hs
@@ -0,0 +1,141 @@
+{-# LANGUAGE CPP #-}
+{-# LANGUAGE ScopedTypeVariables #-}
+
+{-# OPTIONS_GHC -Wall #-}
+
+module Test.QuickCheck.Classes.Semiring
+  ( 
+#if defined(VERSION_semirings)
+    semiringLaws
+#endif
+  ) where
+
+#if defined(VERSION_semirings)
+import Data.Semiring
+import Prelude hiding (Num(..))
+#endif
+
+import Data.Proxy (Proxy)
+import Test.QuickCheck hiding ((.&.))
+import Test.QuickCheck.Property (Property)
+
+import Test.QuickCheck.Classes.Common (Laws(..), myForAllShrink)
+
+#if defined(VERSION_semirings)
+-- | Tests the following properties:
+--
+-- [/Additive Commutativity/]
+--   @a + b ≡ b + a@
+-- [/Additive Left Identity/]
+--   @0 + a ≡ a@
+-- [/Additive Right Identity/]
+--   @a + 0 ≡ a@
+-- [/Multiplicative Associativity/]
+--   @a * (b * c) ≡ (a * b) * c@
+-- [/Multiplicative Left Identity/]
+--   @1 * a ≡ a@
+-- [/Multiplicative Right Identity/]
+--   @a * 1 ≡ a@
+-- [/Multiplication Left Distributes Over Addition/]
+--   @a * (b + c) ≡ (a * b) + (a * c)@
+-- [/Multiplication Right Distributes Over Addition/]
+--   @(a + b) * c ≡ (a * c) + (b * c)@
+-- [/Multiplicative Left Annihilation/]
+--   @0 * a ≡ 0@
+-- [/Multiplicative Right Annihilation/]
+--   @a * 0 ≡ 0@
+semiringLaws :: (Semiring a, Eq a, Arbitrary a, Show a) => Proxy a -> Laws
+semiringLaws p = Laws "Semiring"
+  [ ("Additive Commutativity", semiringCommutativePlus p)
+  , ("Additive Left Identity", semiringLeftIdentityPlus p)
+  , ("Additive Right Identity", semiringRightIdentityPlus p)
+  , ("Multiplicative Associativity", semiringAssociativeTimes p)
+  , ("Multiplicative Left Identity", semiringLeftIdentityTimes p)
+  , ("Multiplicative Right Identity", semiringRightIdentityTimes p)
+  , ("Multiplication Left Distributes Over Addition", semiringLeftMultiplicationDistributes p)
+  , ("Multiplication Right Distributes Over Addition", semiringRightMultiplicationDistributes p)
+  , ("Multiplicative Left Annihilation", semiringLeftAnnihilation p)
+  , ("Multiplicative Right Annihilation", semiringRightAnnihilation p)
+  ]
+
+semiringLeftMultiplicationDistributes :: forall a. (Semiring a, Eq a, Arbitrary a, Show a) => Proxy a -> Property
+semiringLeftMultiplicationDistributes _ = myForAllShrink True (const True)
+  (\(a :: a,b,c) -> ["a = " ++ show a, "b = " ++ show b, "c = " ++ show c])
+  "a * (b + c)"
+  (\(a,b,c) -> a * (b + c))
+  "(a * b) + (a * c)"
+  (\(a,b,c) -> (a * b) + (a * c))
+
+semiringRightMultiplicationDistributes :: forall a. (Semiring a, Eq a, Arbitrary a, Show a) => Proxy a -> Property
+semiringRightMultiplicationDistributes _ = myForAllShrink True (const True)
+  (\(a :: a,b,c) -> ["a = " ++ show a, "b = " ++ show b, "c = " ++ show c])
+  "(a + b) * c"
+  (\(a,b,c) -> c * (a + b))
+  "(a * c) + (b * c)"
+  (\(a,b,c) -> (a * c) + (b * c))
+
+semiringLeftIdentityPlus :: forall a. (Semiring a, Eq a, Arbitrary a, Show a) => Proxy a -> Property
+semiringLeftIdentityPlus _ = myForAllShrink False (const True)
+  (\(a :: a) -> ["a = " ++ show a])
+  "0 + a"
+  (\a -> zero + a)
+  "a"
+  (\a -> a)
+
+semiringRightIdentityPlus :: forall a. (Semiring a, Eq a, Arbitrary a, Show a) => Proxy a -> Property
+semiringRightIdentityPlus _ = myForAllShrink False (const True)
+  (\(a :: a) -> ["a = " ++ show a])
+  "a + 0"
+  (\a -> a + zero)
+  "a"
+  (\a -> a)
+
+semiringRightIdentityTimes :: forall a. (Semiring a, Eq a, Arbitrary a, Show a) => Proxy a -> Property
+semiringRightIdentityTimes _ = myForAllShrink False (const True)
+  (\(a :: a) -> ["a = " ++ show a])
+  "a * 1"
+  (\a -> a * one)
+  "a"
+  (\a -> a)
+
+semiringLeftIdentityTimes :: forall a. (Semiring a, Eq a, Arbitrary a, Show a) => Proxy a -> Property
+semiringLeftIdentityTimes _ = myForAllShrink False (const True)
+  (\(a :: a) -> ["a = " ++ show a])
+  "1 * a"
+  (\a -> one * a)
+  "a"
+  (\a -> a)
+
+semiringLeftAnnihilation :: forall a. (Semiring a, Eq a, Arbitrary a, Show a) => Proxy a -> Property
+semiringLeftAnnihilation _ = myForAllShrink False (const True)
+  (\(a :: a) -> ["a = " ++ show a])
+  "0 * a"
+  (\a -> zero * a)
+  "0"
+  (\_ -> zero)
+
+semiringRightAnnihilation :: forall a. (Semiring a, Eq a, Arbitrary a, Show a) => Proxy a -> Property
+semiringRightAnnihilation _ = myForAllShrink False (const True)
+  (\(a :: a) -> ["a = " ++ show a])
+  "a * 0"
+  (\a -> a * zero)
+  "0"
+  (\_ -> zero)
+
+semiringCommutativePlus :: forall a. (Semiring a, Eq a, Arbitrary a, Show a) => Proxy a -> Property
+semiringCommutativePlus _ = myForAllShrink True (const True)
+  (\(a :: a,b) -> ["a = " ++ show a, "b = " ++ show b])
+  "a + b"
+  (\(a,b) -> a + b)
+  "b + a"
+  (\(a,b) -> b + a)
+
+semiringAssociativeTimes :: forall a. (Semiring a, Eq a, Arbitrary a, Show a) => Proxy a -> Property
+semiringAssociativeTimes _ = myForAllShrink True (const True)
+  (\(a :: a,b,c) -> ["a = " ++ show a, "b = " ++ show b, "c = " ++ show c])
+  "a * (b * c)"
+  (\(a,b,c) -> a * (b * c))
+  "(a * b) * c"
+  (\(a,b,c) -> (a * b) * c)
+
+#endif
diff --git a/test/Spec.hs b/test/Spec.hs
--- a/test/Spec.hs
+++ b/test/Spec.hs
@@ -33,9 +33,6 @@
 main :: IO ()
 main = lawsCheckMany allPropsApplied
 
--- Only needed to make GHC 7.4 content.
-data Proxy1 (f :: * -> *) = Proxy1
-
 allPropsApplied :: [(String,[Laws])]
 allPropsApplied = 
   [ ("Int",allLaws (Proxy :: Proxy Int))
