diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -4,6 +4,14 @@
 CHANGELOG](http://keepachangelog.com/). This project adheres to [Semantic
 Versioning](http://semver.org/).
 
+## [Unreleased][unreleased]
+### Changed
+- `Serial` instances instead `Proxy` where possible.
+
+### Added
+- Default tests for type constructors parametrized with `()`.
+- Exhaustive `TestTree`s.
+
 ## [0.2] - 2015-09-04
 ### Removed
 - `smallcheck` specific modules from
@@ -13,4 +21,5 @@
 ### Changed
 - Simplify module hierarchy: `Test.Tasty.SmallCheck.Laws` -> `Test.Tasty.Laws`
 
+[unreleased]: https://github.com/jdnavarro/tasty-laws/compare/v0.2...HEAD
 [0.2]: https://github.com/jdnavarro/tasty-laws/compare/bf1caa5...v0.2
diff --git a/README.md b/README.md
--- a/README.md
+++ b/README.md
@@ -3,7 +3,7 @@
 [![Hackage Version](https://img.shields.io/hackage/v/tasty-laws.svg)](https://hackage.haskell.org/package/tasty-laws)
 [![Build Status](https://img.shields.io/travis/jdnavarro/tasty-laws.svg)](https://travis-ci.org/jdnavarro/tasty-laws)
 
-Preassembled `tasty` runners for property testing the following laws:
+Preassembled `tasty` `TestTree`s for property testing the following laws:
 
 - Monoids
 - Functors
diff --git a/Test/Tasty/Laws/Applicative.hs b/Test/Tasty/Laws/Applicative.hs
--- a/Test/Tasty/Laws/Applicative.hs
+++ b/Test/Tasty/Laws/Applicative.hs
@@ -1,7 +1,16 @@
 {-# LANGUAGE CPP #-}
 {-# LANGUAGE FlexibleContexts #-}
 {-# LANGUAGE ScopedTypeVariables #-}
-module Test.Tasty.Laws.Applicative where
+-- | This module is intended to be imported @qualified@, for example:
+--
+-- > import qualified Test.Tasty.Laws.Applicative as Applicative
+--
+module Test.Tasty.Laws.Applicative
+  ( test
+  , testMono
+  , testMonoExhaustive
+  , module Test.SmallCheck.Laws.Applicative
+  ) where
 
 #if !MIN_VERSION_base(4,8,0)
 import Control.Applicative (Applicative)
@@ -11,39 +20,78 @@
 import Test.Tasty (TestTree, testGroup)
 import Test.Tasty.SmallCheck (testProperty)
 import Test.SmallCheck.Series (Series, Serial(series))
+import Test.SmallCheck.Laws.Applicative
+  ( identity
+  , composition
+  , compositionSum
+  , homomorphism
+  , homomorphismSum
+  , interchange
+  , interchangeSum
+  )
 
-import qualified Test.SmallCheck.Laws.Applicative as Applicative
-import Test.Tasty.Laws.Functor
+import qualified Test.Tasty.Laws.Functor as Functor
 
--- | @tasty@ 'TestTree' for 'Applicative' laws. You need to provide the type
---   wrapped in a `Proxy` and make sure 'a' is an instance of 'Serial'.
-testApplicative
+-- | @tasty@ 'TestTree' for 'Applicative' laws. The type signature forces the
+--   parameter to be '()' which, unless you are dealing with non-total
+--   functions, should be enough to test any 'Applicative's.
+test
+  :: ( Applicative f
+     , Eq (f ()), Eq (f (f ())), Show (f ()), Show (f (() -> ()))
+     , Serial Identity (f ())
+     , Serial IO (f ()), Serial IO (f (() -> ()))
+     )
+  => Series IO (f ()) -> TestTree
+test = testMonoExhaustive
+
+-- | @tasty@ 'TestTree' for 'Applicative' laws. Monomorphic sum 'Series'.
+testMono
   :: forall f a .
      ( Applicative f
-     , Show a, Eq a
-     , Show (f a), Eq (f a), (Eq (f (f a)))
-     , Show (f (a -> a))
-     , Serial IO a
-     , Serial IO (f a)
-     , Serial IO (a -> a)
-     , Serial IO (f (a -> a))
+     , Eq a, Eq (f a), (Eq (f (f a)))
+     , Show a, Show (f a), Show (f (a -> a))
      , Serial Identity a, Serial Identity (f a)
+     , Serial IO a, Serial IO (f a), Serial IO (a -> a), Serial IO (f (a -> a))
      )
-  => Proxy (f a) -> TestTree
-testApplicative proxy = testGroup "Applicative"
-  [ testFunctor proxy
-  , testProperty "pure id <*> v ≡ v"
-  $ Applicative.identity (series :: Series IO (f a))
-  , testProperty "(.) <$> u <*> v <*> w ≡  u <*> (v <*> w)"
-  $ Applicative.composition
+  => Series IO (f a) -> TestTree
+testMono fs = testGroup "Applicative"
+  [ Functor.testMono fs
+  , testProperty "pure id <*> v ≡ v" $ identity fs
+  , testProperty "(.) <$> u <*> v <*> w ≡  u <*> (v <*> w)" $ compositionSum
       (series :: Series IO (f (a -> a)))
       (series :: Series IO (f a))
       (series :: Series IO (f (a -> a)))
-  , testProperty "pure f <*> pure x ≡ pure (f x)" $ Applicative.homomorphism
-      (Proxy :: Proxy f)
+  , testProperty "pure f <*> pure x ≡ pure (f x)" $ homomorphismSum
+      (Proxy  :: Proxy f)
       (series :: Series IO a)
       (series :: Series IO (a -> a))
-  , testProperty "u <*> pure y ≡ pure ($ y) <*> u" $ Applicative.interchange
+  , testProperty "u <*> pure y ≡ pure ($ y) <*> u" $ interchangeSum
+      (series :: Series IO a)
+      (series :: Series IO (f (a -> a)))
+  ]
+
+-- | @tasty@ 'TestTree' for 'Applicative' laws. Monomorphic product 'Series'.
+testMonoExhaustive
+  :: forall f a .
+     ( Applicative f
+     , Eq a, Eq (f a), (Eq (f (f a)))
+     , Show a, Show (f a), Show (f (a -> a))
+     , Serial Identity a, Serial Identity (f a)
+     , Serial IO a, Serial IO (f a), Serial IO (a -> a), Serial IO (f (a -> a))
+     )
+  => Series IO (f a) -> TestTree
+testMonoExhaustive fs = testGroup "Applicative"
+  [ Functor.testMonoExhaustive fs
+  , testProperty "pure id <*> v ≡ v" $ identity fs
+  , testProperty "(.) <$> u <*> v <*> w ≡  u <*> (v <*> w)" $ composition
+      (series :: Series IO (f (a -> a)))
+      (series :: Series IO (f a))
+      (series :: Series IO (f (a -> a)))
+  , testProperty "pure f <*> pure x ≡ pure (f x)" $ homomorphism
+      (Proxy  :: Proxy f)
+      (series :: Series IO a)
+      (series :: Series IO (a -> a))
+  , testProperty "u <*> pure y ≡ pure ($ y) <*> u" $ interchange
       (series :: Series IO a)
       (series :: Series IO (f (a -> a)))
   ]
diff --git a/Test/Tasty/Laws/Functor.hs b/Test/Tasty/Laws/Functor.hs
--- a/Test/Tasty/Laws/Functor.hs
+++ b/Test/Tasty/Laws/Functor.hs
@@ -1,29 +1,121 @@
 {-# LANGUAGE FlexibleContexts #-}
 {-# LANGUAGE ScopedTypeVariables #-}
-module Test.Tasty.Laws.Functor where
+-- | This module is intended to be imported @qualified@, for example:
+--
+-- > import qualified Test.Tasty.Laws.Functor as Functor
+--
+module Test.Tasty.Laws.Functor
+  ( test
+  , testMono
+  , testMonoExhaustive
+  , testPoly
+  , testPolyExhaustive
+  , module Test.SmallCheck.Laws.Functor
+  ) where
 
-import Data.Proxy (Proxy)
+import Data.Proxy
 import Data.Functor.Identity (Identity)
 import Test.Tasty (TestTree, testGroup)
-import Test.Tasty.SmallCheck (testProperty)
+import Test.Tasty.SmallCheck (testProperty, Testable)
+import Test.SmallCheck.Laws.Functor (identity, composition, compositionSum)
 import Test.SmallCheck.Series (Serial(series), Series)
 
-import qualified Test.SmallCheck.Laws.Functor as Functor
+-- | @tasty@ 'TestTree' for 'Functor' laws. The type signature forces the
+--   parameter to be '()' which, unless you are dealing non-total functions,
+--   should be enough to test any 'Functor's.
+test :: (Functor f, Eq (f ()), Show (f ())) => Series IO (f ()) -> TestTree
+test = testMonoExhaustive
 
--- | @tasty@ 'TestTree' for 'Functor' laws. You need to provide the type
---   wrapped in a `Proxy` and make sure 'a' is an instance of 'Serial'.
-testFunctor
+-- | @tasty@ 'TestTree' for 'Functor' laws. Monomorphic sum 'Series' for @f@
+--   and @g@ in the compose law.
+--
+-- @
+-- fmap (\a -> a) . (\a -> a) == fmap (\a -> a) . fmap (\a -> a)
+-- fmap (\b -> b) . (\b -> b) == fmap (\b -> b) . fmap (\b -> b)
+-- ...
+-- @
+testMono
   :: forall f a .
-     ( Eq (f a), Eq (f (f a)), Functor f, Show a, Show (f a)
-     , Serial IO (f a)
+     ( Eq (f a), Functor f, Show a, Show (f a)
+     , Serial Identity a
      , Serial IO (a -> a)
-     , Serial Identity a, Serial Identity (f a)
      )
-  => Proxy (f a) -> TestTree
-testFunctor _ = testGroup "Functor laws"
-  [ testProperty "fmap id ≡ id" $ Functor.identity (series :: Series IO (f a))
-  , testProperty "fmap (f . g) ≡ fmap f . fmap g" $ Functor.composition
-      (series :: Series IO (f a))
-      (series :: Series IO (a -> a))
-      (series :: Series IO (a -> a))
+  => Series IO (f a) -> TestTree
+testMono = testWithComp $ \fs ->
+    compositionSum fs (series :: Series IO (a -> a))
+                      (series :: Series IO (a -> a))
+
+-- | @tasty@ 'TestTree' for 'Functor' laws. Monomorphic product 'Series' for
+--   @f@ and @g@ in the compose law.
+--
+-- @
+-- fmap (\a -> a) . (\a -> a) == fmap (\a -> a) . fmap (\a -> a)
+-- fmap (\a -> a) . (\a -> b) == fmap (\a -> a) . fmap (\a -> b)
+-- fmap (\a -> a) . (\b -> b) == fmap (\a -> a) . fmap (\b -> b)
+-- ...
+-- @
+testMonoExhaustive
+  :: forall f a .
+     ( Eq (f a), Functor f, Show a, Show (f a)
+     , Serial Identity a
+     , Serial IO (a -> a)
+     )
+  => Series IO (f a) -> TestTree
+testMonoExhaustive = testWithComp $ \fs ->
+    composition fs (series :: Series IO (a -> a))
+                   (series :: Series IO (a -> a))
+
+-- | @tasty@ 'TestTree' for 'Functor' laws. Polymorphic sum 'Series' for
+--   @f@ and @g@ in the compose law.
+--
+-- @
+-- fmap (\a0 -> b0) . (\b0 -> c0) == fmap (\a0 -> b0) . fmap (\b0 -> c0)
+-- fmap (\a1 -> b1) . (\b1 -> c1) == fmap (\a1 -> a1) . fmap (\b1 -> c1)
+-- fmap (\a2 -> b2) . (\b2 -> c2) == fmap (\a2 -> a2) . fmap (\b2 -> c2)
+-- ...
+-- @
+testPoly
+  :: forall f a b c .
+     ( Functor f
+     , Eq (f a), Show a, Show (f a) , Serial Identity a
+     , Eq (f b), Show b, Show (f b) , Serial Identity b
+     , Eq (f c), Show c, Show (f c) , Serial Identity c
+     , Serial IO (a -> b), Serial IO (b -> c)
+     )
+  => Proxy b -> Proxy c -> Series IO (f a) -> TestTree
+testPoly _ _ = testWithComp $ \fs ->
+    compositionSum fs (series :: Series IO (b -> c))
+                      (series :: Series IO (a -> b))
+
+-- | @tasty@ 'TestTree' for 'Functor' laws. Polymorphic product 'Series' for
+--   @f@ and @g@ in the compose law.
+--
+-- @
+-- fmap (\a0 -> b0) . (\b0 -> c0) == fmap (\a0 -> b0) . fmap (\b0 -> c0)
+-- fmap (\a0 -> b0) . (\b0 -> c1) == fmap (\a0 -> a0) . fmap (\b0 -> c1)
+-- fmap (\a0 -> b0) . (\b0 -> c0) == fmap (\a0 -> a0) . fmap (\b1 -> c1)
+-- ...
+-- @
+testPolyExhaustive
+  :: forall f a b c .
+     ( Functor f
+     , Eq (f a), Show a, Show (f a) , Serial Identity a
+     , Eq (f b), Show b, Show (f b) , Serial Identity b
+     , Eq (f c), Show c, Show (f c) , Serial Identity c
+     , Serial IO (a -> b), Serial IO (b -> c)
+     )
+  => Proxy b -> Proxy c -> Series IO (f a) -> TestTree
+testPolyExhaustive _ _ = testWithComp $ \fs ->
+    composition fs (series :: Series IO (b -> c))
+                   (series :: Series IO (a -> b))
+
+-- * Internal
+
+testWithComp
+  :: (Eq (f a), Functor f, Show (f a), Testable IO r)
+  => (Series IO (f a) -> r) -> Series IO (f a) -> TestTree
+testWithComp comp fs = testGroup "Functor laws"
+  [ testProperty "fmap id ≡ id" $ identity fs
+  , testProperty "fmap (f . g) ≡ fmap f . fmap g"
+    $ comp fs
   ]
diff --git a/Test/Tasty/Laws/Monad.hs b/Test/Tasty/Laws/Monad.hs
--- a/Test/Tasty/Laws/Monad.hs
+++ b/Test/Tasty/Laws/Monad.hs
@@ -1,36 +1,71 @@
 {-# LANGUAGE CPP #-}
 {-# LANGUAGE FlexibleContexts #-}
 {-# LANGUAGE ScopedTypeVariables #-}
-module Test.Tasty.Laws.Monad where
+-- | This module is intended to be imported @qualified@, for example:
+--
+-- > import qualified Test.Tasty.Laws.Monad as Monad
+--
+module Test.Tasty.Laws.Monad
+  ( test
+  , testMono
+  , testMonoExhaustive
+  ) where
 
 #if !MIN_VERSION_base(4,8,0)
 import Control.Applicative (Applicative)
 #endif
 import Data.Functor.Identity (Identity)
-import Data.Proxy (Proxy(..))
 import Test.SmallCheck.Series (Series, Serial(series))
+import Test.SmallCheck.Laws.Monad (associativity, associativitySum)
 import Test.Tasty (TestTree, testGroup)
 import Test.Tasty.SmallCheck (testProperty)
-import qualified Test.SmallCheck.Laws.Monad as Monad
+import qualified Test.Tasty.Laws.Applicative as Applicative
 
-import Test.Tasty.Laws.Applicative
+-- | @tasty@ 'TestTree' for 'Monad' laws. The type signature forces the
+--   parameter to be '()' which, unless you are dealing with non-total
+--   functions, should be enough to test any 'Monad's.
+test
+  :: ( Applicative m, Monad m
+     , Eq (m ()), Eq (m (m ()))
+     , Show (m ()), Show (m (() -> ()))
+     , Serial Identity (m ())
+     , Serial IO (m ()), Serial IO (m (() -> ()))
+     )
+  => Series IO (m ()) -> TestTree
+test = testMonoExhaustive
 
--- | @tasty@ 'TestTree' for 'Monad' laws. You need to provide the type
---   wrapped in a `Proxy` and make sure 'a' is an instance of 'Serial'.
-testMonad
-  :: forall f a .
-     ( Applicative f, Monad f
-     , Show a, Show (f a), Show (f (a -> a))
-     , Eq a, Eq (f a), Eq (f (f a))
+-- | @tasty@ 'TestTree' for 'Monad' laws. Monomorphic sum 'Series'.
+testMono
+  :: forall m a .
+     ( Applicative m, Monad m
+     , Eq a, Eq (m a), Eq (m (m a))
+     , Show a, Show (m a), Show (m (a -> a))
+     , Serial Identity a, Serial Identity (m a)
      , Serial IO a, Serial IO (a -> a)
-     , Serial IO (f a) ,Serial IO (f (a -> a)), Serial IO (a -> f a)
-     , Serial Identity a, Serial Identity (f a)
+     , Serial IO (m a) ,Serial IO (m (a -> a)), Serial IO (a -> m a)
      )
-  => Proxy (f a) -> TestTree
-testMonad proxy = testGroup "Monad laws"
-  [ testApplicative proxy
+  => Series IO (m a) -> TestTree
+testMono ms = testGroup "Monad laws"
+  [ Applicative.testMono ms
   , testProperty "(m >>= f) >>= g ≡ m (f >=> g)"
-  $ Monad.associativity (series :: Series IO (f a))
-                        (series :: Series IO (a -> f a))
-                        (series :: Series IO (a -> f a))
+  $ associativitySum ms (series :: Series IO (a -> m a))
+                        (series :: Series IO (a -> m a))
+  ]
+
+-- | @tasty@ 'TestTree' for 'Monad' laws. Monomorphic product 'Series'.
+testMonoExhaustive
+  :: forall m a .
+     ( Applicative m, Monad m
+     , Eq a, Eq (m a), Eq (m (m a))
+     , Show a, Show (m a), Show (m (a -> a))
+     , Serial Identity a, Serial Identity (m a)
+     , Serial IO a, Serial IO (a -> a)
+     , Serial IO (m a) ,Serial IO (m (a -> a)), Serial IO (a -> m a)
+     )
+  => Series IO (m a) -> TestTree
+testMonoExhaustive ms = testGroup "Monad laws"
+  [ Applicative.testMono ms
+  , testProperty "(m >>= f) >>= g ≡ m (f >=> g)"
+    $ associativity ms (series :: Series IO (a -> m a))
+                       (series :: Series IO (a -> m a))
   ]
diff --git a/Test/Tasty/Laws/Monoid.hs b/Test/Tasty/Laws/Monoid.hs
--- a/Test/Tasty/Laws/Monoid.hs
+++ b/Test/Tasty/Laws/Monoid.hs
@@ -1,26 +1,63 @@
 {-# LANGUAGE CPP #-}
-{-# LANGUAGE FlexibleContexts #-}
-{-# LANGUAGE ScopedTypeVariables #-}
-module Test.Tasty.Laws.Monoid where
+-- | This module is intended to be imported @qualified@:
+--
+-- > import qualified Test.Tasty.Laws.Monoid as Monoid
+--
+module Test.Tasty.Laws.Monoid
+  ( test
+  , testExhaustive
+  , testMConcat
+  , module Test.SmallCheck.Laws.Monoid
+  ) where
 
 #if !MIN_VERSION_base(4,8,0)
 import Data.Monoid (Monoid)
 #endif
-import Data.Proxy (Proxy)
-import Test.SmallCheck.Series (Series, Serial(series))
+
+import Test.SmallCheck.Series (Series)
+import Test.SmallCheck.Laws.Monoid
+  ( leftIdentity
+  , rightIdentity
+  , associativity
+  , associativitySum
+  , mconcatProp
+  )
 import Test.Tasty (TestTree, testGroup)
 import Test.Tasty.SmallCheck (testProperty)
 
-import qualified Test.SmallCheck.Laws.Monoid as Monoid
+-- | @tasty@ 'TestTree' for 'Monoid' laws. Sum of series for associativity law.
+--
+-- @
+-- ('a' <> 'a') <> 'a' == 'a' <> ('a' <> 'a')
+-- ('b' <> 'b') <> 'b' == 'b' <> ('b' <> 'b')
+-- ('c' <> 'c') <> 'c' == 'c' <> ('c' <> 'c')
+-- ...
+-- @
+test :: (Eq a, Show a, Monoid a) => Series IO a -> TestTree
+test ms = testGroup "Monoid laws"
+  [ testProperty "mempty <> x ≡ x" $ leftIdentity ms
+  , testProperty "x <> mempty ≡ x" $ rightIdentity ms
+  , testProperty "x <> (y <> z) ≡ (x <> y) <> z"
+        $ associativitySum ms ms ms
+  ]
 
--- | @tasty@ 'TestTree' for 'Applicative' laws. You need to provide the type
---   wrapped in a `Proxy` and make sure 'a' is an instance of 'Serial'.
-testMonoid :: forall a . (Show a, Eq a, Monoid a, Serial IO a) => Proxy a -> TestTree
-testMonoid _ = testGroup "Monoid laws"
-  [ testProperty "mempty <> x ≡ x" $ Monoid.leftIdentity (series :: Series IO a)
-  , testProperty "x <> mempty ≡ x" $ Monoid.rightIdentity (series :: Series IO a)
+-- | @tasty@ 'TestTree' for 'Monoid' laws. Product of series for associativity
+--   law. Be aware of combinatorial explosion.
+--
+-- @
+-- ('a' <> 'a') <> 'a' == 'a' <> ('a' <> 'a')
+-- ('a' <> 'a') <> 'b' == 'a' <> ('a' <> 'b')
+-- ('a' <> 'b') <> 'b' == 'a' <> ('b' <> 'b')
+-- ...
+-- @
+testExhaustive :: (Eq a, Show a, Monoid a) => Series IO a -> TestTree
+testExhaustive ms = testGroup "Monoid laws"
+  [ testProperty "mempty <> x ≡ x" $ leftIdentity ms
+  , testProperty "x <> mempty ≡ x" $ rightIdentity ms
   , testProperty "x <> (y <> z) ≡ (x <> y) <> z"
-  $ Monoid.associativity (series :: Series IO a) series series
-  , testProperty "mconcat ≡ foldr mappend mempty"
-  $ Monoid.mconcat (series :: Series IO a)
+        $ associativity ms ms ms
   ]
+
+-- | Use this test when implementing the 'mconcat' method.
+testMConcat :: (Eq a, Show a, Monoid a) => Series IO a -> TestTree
+testMConcat ms = testProperty "mconcat ≡ foldr mappend mempty" $ mconcatProp ms
diff --git a/stack.yaml b/stack.yaml
--- a/stack.yaml
+++ b/stack.yaml
@@ -2,6 +2,6 @@
 packages:
 - '.'
 extra-deps:
-- smallcheck-laws-0.2
+- smallcheck-laws-0.3
 - smallcheck-series-0.5.1
 resolver: lts-3.4
diff --git a/tasty-laws.cabal b/tasty-laws.cabal
--- a/tasty-laws.cabal
+++ b/tasty-laws.cabal
@@ -1,13 +1,15 @@
 name:                tasty-laws
-version:             0.2
+version:             0.3
 synopsis:            Test common laws
 description:
-  Preassembled 'tasty' runners for property testing 'Monoid', 'Functor',
+  Preassembled 'tasty' 'TestTree's for property testing 'Monoid', 'Functor',
   'Applicative' and 'Monad' laws.
 license:             BSD3
 license-file:        LICENSE
 author:              Danny Navarro
 maintainer:          j@dannynavarro.net
+homepage:            https://github.com/jdnavarro/tasty-laws
+bug-reports:         https://github.com/jdnavarro/tasty-laws/issues
 category:            Testing
 build-type:          Simple
 cabal-version:       >=1.10
@@ -26,7 +28,7 @@
                        Test.Tasty.Laws.Monoid
   build-depends:       base >=4.6 && <4.9,
                        smallcheck >=1.1.1,
-                       smallcheck-laws >=0.1,
+                       smallcheck-laws >=0.3,
                        smallcheck-series >=0.3,
                        tasty >=0.10,
                        tasty-smallcheck >=0.8.0.1
@@ -45,7 +47,7 @@
   build-depends:       base >=4.6 && <4.9,
                        smallcheck >=1.1.1,
                        tasty >=0.10,
-                       smallcheck-laws >=0.1,
+                       smallcheck-laws >=0.3,
                        tasty-laws
 
   if impl(ghc < 7.8)
diff --git a/tests/tasty.hs b/tests/tasty.hs
--- a/tests/tasty.hs
+++ b/tests/tasty.hs
@@ -8,15 +8,14 @@
 import Control.Applicative ((<$>))
 #endif
 import Data.Monoid (Sum(..), Product(..))
-import Data.Proxy (Proxy(..))
 
-import Test.SmallCheck.Series (Serial(series))
+import Test.SmallCheck.Series (Series, Serial(series))
 import Test.Tasty (TestTree, defaultMain, testGroup)
 
-import Test.Tasty.Laws.Applicative
-import Test.Tasty.Laws.Functor
-import Test.Tasty.Laws.Monad
-import Test.Tasty.Laws.Monoid
+import qualified Test.Tasty.Laws.Applicative as Applicative
+import qualified Test.Tasty.Laws.Functor as Functor
+import qualified Test.Tasty.Laws.Monad as Monad
+import qualified Test.Tasty.Laws.Monoid as Monoid
 
 main :: IO ()
 main = defaultMain $ testGroup "Laws"
@@ -26,74 +25,90 @@
      , monadTests
      ]
 
+instance (Monad m, Serial m a) => Serial m (Sum a) where
+    series = Sum <$> series
+
+instance (Monad m, Serial m a) => Serial m (Product a) where
+    series = Product <$> series
+
 monoidTests :: TestTree
 monoidTests = testGroup "Monoid"
-  [ testGroup "Sum"
-    [ testGroup "Int"
-      [ testMonoid (Proxy :: Proxy (Sum Int)) ]
+  [ testGroup "Product"
+     [ testGroup "Int"
+      [ Monoid.test (series :: Series IO (Product Int)) ]
     , testGroup "Integer"
-      [ testMonoid (Proxy :: Proxy (Sum Integer)) ]
+      [ Monoid.test (series :: Series IO (Product Integer)) ]
     , testGroup "Float"
-      [ testMonoid (Proxy :: Proxy (Sum Float)) ]
+      [ Monoid.test (series :: Series IO (Product Float)) ]
     ]
-  , testGroup "Product"
-     [ testGroup "Int"
-      [ testMonoid (Proxy :: Proxy (Product Int)) ]
+  , testGroup "Exhausitive Sum"
+    [ testGroup "Int"
+      [ Monoid.testExhaustive (series :: Series IO (Sum Int)) ]
     , testGroup "Integer"
-      [ testMonoid (Proxy :: Proxy (Product Integer)) ]
+      [ Monoid.testExhaustive (series :: Series IO (Sum Integer)) ]
     , testGroup "Float"
-      [ testMonoid (Proxy :: Proxy (Product Float)) ]
+      [ Monoid.testExhaustive (series :: Series IO (Sum Float)) ]
     ]
   ]
 
 functorTests :: TestTree
 functorTests = testGroup "Functor"
   [ testGroup "Maybe"
-    [ testGroup "Int"
-      [ testFunctor (Proxy :: Proxy (Maybe Int)) ]
+    [ testGroup "Unit"
+      [ Functor.test (series :: Series IO (Maybe ())) ]
+    , testGroup "Int"
+      [ Functor.testMono (series :: Series IO (Maybe Int)) ]
     , testGroup "Char"
-      [ testFunctor (Proxy :: Proxy (Maybe Char)) ]
+      [ Functor.testMono (series :: Series IO (Maybe Char)) ]
+    , testGroup "Bool"
+      [ Functor.testMonoExhaustive (series :: Series IO (Maybe Bool)) ]
     ]
   , testGroup "[]"
-    [ testGroup "Bool"
-      [ testFunctor (Proxy :: Proxy [Bool]) ]
+    [ testGroup "Unit"
+      [ Functor.test (series :: Series IO [()]) ]
+    , testGroup "Bool"
+      [ Functor.testMono (series :: Series IO [Bool]) ]
     , testGroup "Int"
-      [ testFunctor (Proxy :: Proxy [Int]) ]
+      [ Functor.testMono (series :: Series IO [Int]) ]
     ]
   ]
 
 applicativeTests :: TestTree
 applicativeTests = testGroup "Applicative"
   [ testGroup "Maybe"
-    [ testGroup "Int"
-      [ testApplicative (Proxy :: Proxy (Maybe Int)) ]
+    [ testGroup "Unit"
+      [ Applicative.test (series :: Series IO (Maybe ())) ]
+    , testGroup "Bool"
+      [ Applicative.testMonoExhaustive (series :: Series IO (Maybe Bool)) ]
+    , testGroup "Int"
+      [ Applicative.testMono (series :: Series IO (Maybe Int)) ]
     , testGroup "Float"
-      [ testApplicative (Proxy :: Proxy (Maybe Float)) ]
+      [ Applicative.testMono (series :: Series IO (Maybe Float)) ]
     ]
   , testGroup "[]"
-    [ testGroup "Bool"
-      [ testApplicative (Proxy :: Proxy [Bool]) ]
-    , testGroup "Char"
-      [ testApplicative (Proxy :: Proxy [Char]) ]
+    [ testGroup "Unit"
+      [ Applicative.test (series :: Series IO [()]) ]
+    , testGroup "Bool"
+      [ Applicative.testMono (series :: Series IO [Bool]) ]
+    -- , testGroup "Char"
+    --   [ Applicative.testMono (series :: Series IO [Char]) ]
     ]
   ]
 
 monadTests :: TestTree
 monadTests = testGroup "Monad"
   [ testGroup "Maybe"
-    [ testGroup "()"
-      [ testMonad (Proxy :: Proxy (Maybe ())) ]
+    [ testGroup "Unit"
+      [ Monad.test (series :: Series IO (Maybe ())) ]
+    , testGroup "Bool"
+      [ Monad.testMonoExhaustive (series :: Series IO (Maybe Bool)) ]
     , testGroup "Int"
-      [ testMonad (Proxy :: Proxy (Maybe Int)) ]
+      [ Monad.testMono (series :: Series IO (Maybe Int)) ]
     ]
   , testGroup "[]"
-    [ testGroup "()"
-      [ testMonad (Proxy :: Proxy [()]) ]
+    [ testGroup "Unit"
+      [ Monad.test (series :: Series IO [()]) ]
+    , testGroup "Bool"
+      [ Monad.testMono (series :: Series IO [Bool]) ]
     ]
   ]
-
-instance (Monad m, Serial m a) => Serial m (Sum a) where
-    series = Sum <$> series
-
-instance (Monad m, Serial m a) => Serial m (Product a) where
-    series = Product <$> series
