diff --git a/LICENSE b/LICENSE
new file mode 100644
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,30 @@
+Copyright Tony Day (c) 2016
+
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+    * Redistributions of source code must retain the above copyright
+      notice, this list of conditions and the following disclaimer.
+
+    * Redistributions in binary form must reproduce the above
+      copyright notice, this list of conditions and the following
+      disclaimer in the documentation and/or other materials provided
+      with the distribution.
+
+    * Neither the name of Tony Day nor the names of other
+      contributors may be used to endorse or promote products derived
+      from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/Setup.hs b/Setup.hs
new file mode 100644
--- /dev/null
+++ b/Setup.hs
@@ -0,0 +1,2 @@
+import Distribution.Simple
+main = defaultMain
diff --git a/numhask-test.cabal b/numhask-test.cabal
new file mode 100644
--- /dev/null
+++ b/numhask-test.cabal
@@ -0,0 +1,55 @@
+name:           numhask-test
+version:        0.1.0.0
+synopsis:       Laws and tests for numhask
+description:    Laws and tests for numhask.
+category:       mathematics
+homepage:       https://github.com/tonyday567/numhask#readme
+bug-reports:    https://github.com/tonyday567/numhask/issues
+author:         Tony Day
+maintainer:     tonyday567@gmail.com
+copyright:      Tony Day
+license:        BSD3
+license-file:   LICENSE
+build-type:     Simple
+cabal-version:  >= 1.18
+
+extra-source-files:
+    stack.yaml
+
+source-repository head
+  type: git
+  location: https://github.com/tonyday567/numhask
+
+library
+  hs-source-dirs:
+      src
+  default-extensions: NegativeLiterals NoImplicitPrelude OverloadedStrings UnicodeSyntax
+  ghc-options:
+      -Wall
+      -Wcompat
+      -Wincomplete-record-updates
+      -Wincomplete-uni-patterns
+      -Wredundant-constraints
+  build-depends:
+      QuickCheck >=2.8 && <3
+    , base >=4.7 && <4.12
+    , numhask-prelude >=0.1.0.0 && <0.2
+    , tasty >= 1.0.1.1 && <1.2
+    , tasty-quickcheck >= 0.9.2 && <1.0
+  exposed-modules:
+      NumHask.Laws
+  default-language: Haskell2010
+
+test-suite test
+  type: exitcode-stdio-1.0
+  main-is: test.hs
+  hs-source-dirs:
+      test
+  default-extensions: NegativeLiterals NoImplicitPrelude OverloadedStrings UnicodeSyntax
+  build-depends:
+      base >=4.7 && <5
+    , QuickCheck >=2.8 && <3
+    , numhask-test
+    , numhask-prelude >= 0.1.0.0 && < 0.2
+    , tasty
+  default-language: Haskell2010
diff --git a/src/NumHask/Laws.hs b/src/NumHask/Laws.hs
new file mode 100644
--- /dev/null
+++ b/src/NumHask/Laws.hs
@@ -0,0 +1,661 @@
+{-# LANGUAGE ScopedTypeVariables #-}
+{-# LANGUAGE FlexibleContexts #-}
+{-# LANGUAGE RankNTypes #-}
+{-# LANGUAGE OverloadedStrings #-}
+{-# LANGUAGE RebindableSyntax #-}
+{-# OPTIONS_GHC -fno-warn-type-defaults #-}
+
+module NumHask.Laws
+  ( LawArity(..)
+  , LawArity2(..)
+  , Law
+  , Law2
+  , testLawOf
+  , testLawOf2
+  , idempotentLaws
+  , additiveLaws
+  , additiveLaws_
+  , additiveLawsFail
+  , additiveGroupLaws
+  , multiplicativeLaws
+  , multiplicativeLawsFail
+  , multiplicativeMonoidalLaws
+  , multiplicativeGroupLaws
+  , multiplicativeGroupLaws_
+  , distributionLaws
+  , distributionLawsFail
+  , integralLaws
+  , rationalLaws
+  , signedLaws
+  , normedLaws
+  , normedBoundedLaws
+  , metricIntegralLaws
+  , metricIntegralBoundedLaws
+  , metricRationalLaws
+  , upperBoundedFieldLaws
+  , lowerBoundedFieldLaws
+  , quotientFieldLaws 
+  , expFieldLaws
+  , additiveBasisLaws
+  , additiveGroupBasisLaws
+  , multiplicativeBasisLaws
+  , multiplicativeGroupBasisLaws
+  , additiveModuleLaws
+  , additiveGroupModuleLaws
+  , multiplicativeModuleLaws
+  , multiplicativeGroupModuleLawsFail
+  , expFieldContainerLaws
+  , tensorProductLaws
+  , banachLaws
+  , hilbertLaws
+  , semiringLaws
+  , ringLaws
+  , starSemiringLaws
+  , involutiveRingLaws
+  , integralsLaws
+  ) where
+
+import NumHask.Prelude
+import Test.Tasty.QuickCheck hiding ((><))
+import Test.Tasty (TestName, TestTree)
+
+smallRational :: (FromRatio a) => a
+smallRational = 10.0
+
+smallRationalPower :: (FromRatio a) => a
+smallRationalPower = 6.0
+
+smallIntegralPower :: (FromInteger a) => a
+smallIntegralPower = 6
+
+-- | unification of law equations
+data LawArity a
+  = Nonary Bool
+  | Unary (a -> Bool)
+  | Binary (a -> a -> Bool)
+  | Ternary (a -> a -> a -> Bool)
+  | Ornary (a -> a -> a -> a -> Bool)
+  | Failiary (a -> Property)
+
+type Law a = (TestName, LawArity a)
+
+-- | unification of law equations with 2 types
+data LawArity2 a b
+  = Unary10 (a -> Bool)
+  | Unary01 (b -> Bool)
+  | Binary11 (a -> b -> Bool)
+  | Binary20 (a -> a -> Bool)
+  | Ternary21 (a -> a -> b -> Bool)
+  | Ternary12 (a -> b -> b -> Bool)
+  | Ternary30 (a -> a -> a -> Bool)
+  | Quad31 (a -> a -> a -> b -> Bool)
+  | Quad22 (a -> a -> b -> b -> Bool)
+  | Failiary2 (a -> Property)
+
+type Law2 a b = (TestName, LawArity2 a b)
+
+testLawOf :: (Arbitrary a, Show a) => [a] -> Law a -> TestTree
+testLawOf _ (name, Nonary f) = testProperty name f
+testLawOf _ (name, Unary f) = testProperty name f
+testLawOf _ (name, Binary f) = testProperty name f
+testLawOf _ (name, Ternary f) = testProperty name f
+testLawOf _ (name, Ornary f) = testProperty name f
+testLawOf _ (name, Failiary f) = testProperty name f
+
+testLawOf2 ::
+     (Arbitrary a, Show a, Arbitrary b, Show b)
+  => [(a, b)]
+  -> Law2 a b
+  -> TestTree
+testLawOf2 _ (name, Unary10 f) = testProperty name f
+testLawOf2 _ (name, Unary01 f) = testProperty name f
+testLawOf2 _ (name, Binary11 f) = testProperty name f
+testLawOf2 _ (name, Binary20 f) = testProperty name f
+testLawOf2 _ (name, Ternary21 f) = testProperty name f
+testLawOf2 _ (name, Ternary12 f) = testProperty name f
+testLawOf2 _ (name, Ternary30 f) = testProperty name f
+testLawOf2 _ (name, Quad22 f) = testProperty name f
+testLawOf2 _ (name, Quad31 f) = testProperty name f
+testLawOf2 _ (name, Failiary2 f) = testProperty name f
+
+-- idempotent
+idempotentLaws :: (Eq a, Additive a, Multiplicative a) => [Law a]
+idempotentLaws =
+  [ ("idempotent: a + a == a", Unary (\a -> a + a == a))
+  , ("idempotent: a * a == a", Unary (\a -> a * a == a))
+  ]
+
+-- | additive
+additiveLaws :: (Eq a, Additive a) => [Law a]
+additiveLaws =
+  [ ( "associative: (a + b) + c = a + (b + c)"
+    , Ternary (\a b c -> (a + b) + c == a + (b + c)))
+  , ("left id: zero + a = a", Unary (\a -> zero + a == a))
+  , ("right id: a + zero = a", Unary (\a -> a + zero == a))
+  , ("commutative: a + b == b + a", Binary (\a b -> a + b == b + a))
+  ]
+
+-- | additive with approximate association equality
+additiveLaws_ :: (Epsilon a, Additive a) => [Law a]
+additiveLaws_ =
+  [ ( "associative: (a + b) + c ≈ a + (b + c)"
+    , Ternary (\a b c -> (a + b) + c ≈ a + (b + c)))
+  , ("left id: zero + a = a", Unary (\a -> zero + a == a))
+  , ("right id: a + zero = a", Unary (\a -> a + zero == a))
+  , ("commutative: a + b == b + a", Binary (\a b -> a + b == b + a))
+  ]
+
+-- | additive laws with a failure on association
+additiveLawsFail :: (Eq a, Additive a, Show a, Arbitrary a) => [Law a]
+additiveLawsFail =
+  [ ( "associative: (a + b) + c = a + (b + c)"
+    , Failiary $ expectFailure . (\a b c -> (a + b) + c == a + (b + c)))
+  , ("left id: zero + a = a", Unary (\a -> zero + a == a))
+  , ("right id: a + zero = a", Unary (\a -> a + zero == a))
+  , ("commutative: a + b == b + a", Binary (\a b -> a + b == b + a))
+  ]
+
+additiveGroupLaws :: (Eq a, AdditiveGroup a) => [Law a]
+additiveGroupLaws =
+  [ ("minus: a - a = zero", Unary (\a -> (a - a) == zero))
+  , ("negate minus: negate a == zero - a", Unary (\a -> negate a == zero - a))
+  , ( "negate left cancel: negate a + a == zero"
+    , Unary (\a -> negate a + a == zero))
+  , ( "negate right cancel: negate a + a == zero"
+    , Unary (\a -> a + negate a == zero))
+  ]
+
+-- multiplicative
+multiplicativeLaws :: (Eq a, Multiplicative a) => [Law a]
+multiplicativeLaws =
+  [ ( "associative: (a * b) * c = a * (b * c)"
+    , Ternary (\a b c -> (a * b) * c == a * (b * c)))
+  , ("left id: one * a = a", Unary (\a -> one * a == a))
+  , ("right id: a * one = a", Unary (\a -> a * one == a))
+  , ("commutative: a * b == b * a", Binary (\a b -> a * b == b * a))
+  ]
+
+multiplicativeMonoidalLaws ::
+     (Eq a, MultiplicativeUnital a) => [Law a]
+multiplicativeMonoidalLaws =
+  [ ( "associative: (a * b) * c = a * (b * c)"
+    , Ternary (\a b c -> (a `times` b) `times` c == a `times` (b `times` c)))
+  , ("left id: one `times` a = a", Unary (\a -> one `times` a == a))
+  , ("right id: a `times` one = a", Unary (\a -> a `times` one == a))
+  ]
+
+multiplicativeLawsFail ::
+     (Eq a, Show a, Arbitrary a, Multiplicative a) => [Law a]
+multiplicativeLawsFail =
+  [ ( "associative: (a * b) * c = a * (b * c)"
+    , Failiary $ expectFailure . (\a b c -> (a * b) * c == a * (b * c)))
+  , ("left id: one * a = a", Unary (\a -> one * a == a))
+  , ("right id: a * one = a", Unary (\a -> a * one == a))
+  , ("commutative: a * b == b * a", Binary (\a b -> a * b == b * a))
+  ]
+
+multiplicativeGroupLaws :: (Eq a, AdditiveUnital a, MultiplicativeGroup a) => [Law a]
+multiplicativeGroupLaws =
+  [ ( "divide: a == zero || a / a == one"
+    , Unary (\a -> a == zero || (a / a) == one))
+  , ( "recip divide: recip a == one / a"
+    , Unary (\a -> a == zero || recip a == one / a))
+  , ( "recip left: a == zero || recip a * a == one"
+    , Unary (\a -> a == zero || recip a * a == one))
+  , ( "recip right: a == zero || a * recip a == one"
+    , Unary (\a -> a == zero || a * recip a == one))
+  ]
+ 
+multiplicativeGroupLaws_ :: (Epsilon a, MultiplicativeGroup a) => [Law a]
+multiplicativeGroupLaws_ =
+  [ ( "divide: a == zero || a / a ≈ one"
+    , Unary (\a -> a == zero || (a / a) ≈ one))
+  , ( "recip divide: recip a == one / a"
+    , Unary (\a -> a == zero || recip a == one / a))
+  , ( "recip left: a == zero || recip a * a ≈ one"
+    , Unary (\a -> a == zero || recip a * a ≈ one))
+  , ( "recip right: a == zero || a * recip a ≈ one"
+    , Unary (\a -> a == zero || a * recip a ≈ one))
+  ]
+
+-- distribution
+distributionLaws :: (Eq a, Distribution a) => [Law a]
+distributionLaws =
+  [ ( "left annihilation: a * zero == zero"
+    , Unary (\a -> a `times` zero == zero))
+  , ( "right annihilation: zero * a == zero"
+    , Unary (\a -> zero `times` a == zero))
+  , ( "left distributivity: a * (b + c) == a * b + a * c"
+    , Ternary (\a b c -> a `times` (b + c) == a `times` b + a `times` c))
+  , ( "right distributivity: (a + b) * c == a * c + b * c"
+    , Ternary (\a b c -> (a + b) `times` c == a `times` c + b `times` c))
+  ]
+
+distributionLawsFail ::
+     (Show a, Arbitrary a, Epsilon a, Distribution a) => [Law a]
+distributionLawsFail =
+  [ ( "left annihilation: a * zero == zero"
+    , Unary (\a -> a `times` zero == zero))
+  , ( "right annihilation: a * zero == zero"
+    , Unary (\a -> zero `times` a == zero))
+  , ( "left distributivity: a * (b + c) = a * b + a * c"
+    , Failiary $
+      expectFailure . (\a b c -> a `times` (b + c) == a `times` b + a `times` c))
+  , ( "right distributivity: (a + b) * c = a * c + b * c"
+    , Failiary $
+      expectFailure . (\a b c -> (a + b) `times` c == a `times` c + b `times` c))
+  ]
+
+-- integral
+integralLaws :: (Eq a, Integral a, FromInteger a, ToInteger a) => [Law a]
+integralLaws =
+  [ ( "integral divmod: b == zero || b * (a `div` b) + (a `mod` b) == a"
+    , Binary (\a b -> b == zero || b `times` (a `div` b) + (a `mod` b) == a))
+  , ("fromIntegral a = a", Unary (\a -> fromIntegral a == a))
+  ]
+
+-- rational
+rationalLaws :: (Eq a, FromRatio a, ToRatio a) => [Law a]
+rationalLaws =
+  [ ("fromRational a = a", Unary (\a -> fromRational a == a))
+  ]
+
+-- metric
+signedLaws :: (Eq a, Signed a) => [Law a]
+signedLaws = [("sign a * abs a == a", Unary (\a -> sign a `times` abs a == a))]
+
+normedLaws :: forall a b. (Ord b, AdditiveUnital a, AdditiveUnital b, MultiplicativeUnital b, Normed a b) =>
+  [Law2 a b]
+normedLaws =
+  [ ("positive", Binary11 (\a p -> p < (one :: b) || (normLp p a :: b) >= (zero :: b)))
+  , ("preserves zero"
+    , Binary11 (\_ p -> p < (one :: b) || (normLp p (zero :: a) :: b) == (zero :: b)) )
+  ]
+
+normedBoundedLaws :: forall a b. (Eq a, Bounded a, Ord b, AdditiveUnital a, AdditiveUnital b, MultiplicativeUnital b, Normed a b) =>
+  [Law2 a b]
+normedBoundedLaws =
+  [ ("positive or non-minBound", Binary11 (\a p -> a == minBound || p < (one :: b) || (normLp p a :: b) >= (zero :: b)))
+  , ("preserves zero"
+    , Binary11 (\_ p -> p < (one :: b) || (normLp p (zero :: a) :: b) == (zero :: b)) )
+  ]
+
+metricIntegralLaws :: forall a b. (FromInteger b, Ord b, Signed b, Epsilon b, Metric a b, AdditiveGroup b) =>
+  [Law2 a b]
+metricIntegralLaws =
+  [ ("Lp: positive",
+     Ternary21 (\a b p -> p < one || distanceLp p a b >= zero))
+  , ("Lp: zero if equal"
+    , Binary11 (\a p -> p < one || distanceLp p a a == zero))
+  , ( "Lp: associative"
+    , Ternary21 (\a b p ->
+                  p < one ||
+                  p > (smallIntegralPower :: b) ||
+                 distanceLp p a b ≈ distanceLp p b a))
+  , ( "Lp: triangle rule - sum of distances > distance"
+    , Quad31
+        (\a b c p ->
+           (p < one) ||
+           not
+             (veryNegative
+                (distanceLp p a c + distanceLp p b c - distanceLp p a b)) &&
+           not
+             (veryNegative
+                (distanceLp p a b + distanceLp p b c - distanceLp p a c)) &&
+           not
+             (veryNegative
+                (distanceLp p a b + distanceLp p a c - distanceLp p b c))))
+  ]
+
+-- triangle rule doesn't apply to bounded Integrals
+metricIntegralBoundedLaws :: forall a b. (FromInteger b, Bounded b, Ord b, Signed b, Epsilon b, Metric a b) =>
+  [Law2 a b]
+metricIntegralBoundedLaws =
+  [ ("Lp: positive",
+     Ternary21 (\a b p -> p < one || distanceLp p a b >= zero || distanceLp p a b == minBound))
+  , ("Lp: zero if equal"
+    , Binary11 (\a p -> p < one || distanceLp p a a == zero))
+  , ( "Lp: associative"
+    , Ternary21 (\a b p ->
+                  p < one ||
+                  p > (smallIntegralPower :: b) ||
+                 distanceLp p a b ≈ distanceLp p b a))
+  ]
+
+
+metricRationalLaws :: forall a b. (FromRatio b, Ord b, Signed b, Epsilon b, Metric a b, Normed a b, Additive a, AdditiveGroup b) =>
+  [Law2 a b]
+metricRationalLaws =
+  [ ("Lp: positive",
+     Ternary21 (\a b p -> p < one || distanceLp p a b >= zero))
+  , ("Lp: zero if equal"
+    , Binary11 (\a p -> p < one || distanceLp p a a == zero))
+  , ( "Lp: associative"
+    , Ternary21 (\a b p ->
+                  p < one ||
+                  p > (smallRationalPower :: b) ||
+                 distanceLp p a b ≈ distanceLp p b a))
+  , ( "Lp: triangle rule - sum of distances > distance"
+    , Quad31
+        (\a b c p ->
+           (p < one) ||
+           (normL1 a > (smallRational :: b)) ||
+           (normL1 b > (smallRational :: b)) ||
+           (normL1 c > (smallRational :: b)) ||
+           not
+             (veryNegative
+                (distanceLp p a c + distanceLp p b c - distanceLp p a b)) &&
+           not
+             (veryNegative
+                (distanceLp p a b + distanceLp p b c - distanceLp p a c)) &&
+           not
+             (veryNegative
+                (distanceLp p a b + distanceLp p a c - distanceLp p b c))))
+  ]
+
+-- bounded fields
+upperBoundedFieldLaws :: forall a. (Eq a, UpperBoundedField a) => [Law a]
+upperBoundedFieldLaws =
+  [ ( "upper bounded field (infinity) laws"
+    , Unary
+        (\a ->
+           ((one ::a) / zero + infinity == infinity) &&
+           (infinity + a == infinity) &&
+           (zero :: a) / zero /= nan))
+  ]
+
+lowerBoundedFieldLaws :: forall a. (Eq a, LowerBoundedField a) => [Law a]
+lowerBoundedFieldLaws =
+  [ ( "lower bounded field (negative infinity) laws"
+    , Unary
+        (\a ->
+           (negate (one ::a) / zero == negInfinity) &&
+           ((negInfinity :: a) + negInfinity == negInfinity) &&
+           (negInfinity + a == negInfinity)))
+  ]
+
+quotientFieldLaws :: (Field a, QuotientField a Integer, FromInteger a, Ord a) => [Law2 a Integer]
+quotientFieldLaws =
+  [ ( "a - one < floor a <= a <= ceiling a < a + one"
+    , Unary10
+      (\a ->
+        ((a - one) < (fromInteger (floor a)))
+          && (fromInteger (floor a) <= a)
+          && (a <= fromInteger (ceiling a))
+          && (fromInteger (ceiling a) < a + one)
+      )
+    )
+  , ( "round a == floor (a + one/(one+one))"
+    , Unary10
+      (\a -> case even ((floor $ a + one / (one + one)) :: Integer) of
+        True  -> ((round a :: Integer) == (floor $ a + (one / (one + one))))
+        False -> ((round a :: Integer) == (ceiling $ a - (one / (one + one))))
+      )
+    )
+  ] where
+    sign' a
+      | (floor a :: Integer) < 0 = -1
+      | otherwise = 1
+
+expFieldLaws :: forall a b.
+     (FromInteger b, AdditiveUnital b, ExpField a, Normed a b, Epsilon a, Ord a, Ord b) => [Law2 a b]
+expFieldLaws =
+  [ ( "sqrt . (**(one+one)) ≈ id"
+    , Unary10
+        (\a ->
+           not (a > (zero :: a)) ||
+           (normL1 a > (10 :: b)) ||
+           (sqrt . (** (one + one)) $ a) ≈ a &&
+           ((** (one + one)) . sqrt $ a) ≈ a))
+  , ( "log . exp ≈ id"
+    , Unary10
+        (\a ->
+           not (a > (zero :: a)) ||
+           (normL1 a > (10 :: b)) || (log . exp $ a) ≈ a && (exp . log $ a) ≈ a))
+  , ( "for +ive b, a != 0,1: a ** logBase a b ≈ b"
+    , Binary20
+        (\a b ->
+           (not (normL1 b > (zero :: b)) ||
+            not (nearZero (a - zero)) ||
+            (a == one) ||
+            (a == zero && nearZero (logBase a b)) || (a ** logBase a b ≈ b))))
+  ]
+
+expFieldContainerLaws ::
+     ( ExpField (r a)
+     , Foldable r
+     , ExpField a
+     , Epsilon a
+     , Signed a
+     , FromRatio a
+     , Epsilon (r a)
+     , Ord a
+     )
+  => [Law (r a)]
+expFieldContainerLaws =
+  [ ( "sqrt . (**2) ≈ id"
+    , Unary
+        (\a ->
+           not (all veryPositive a) ||
+           any (> smallRational) a ||
+           (sqrt . (** (one + one)) $ a) ≈ a &&
+           ((** (one + one)) . sqrt $ a) ≈ a))
+  , ( "log . exp ≈ id"
+    , Unary
+        (\a ->
+           not (all veryPositive a) ||
+           any (> smallRational) a || (log . exp $ a) ≈ a && (exp . log $ a) ≈ a))
+  , ( "for +ive b, a != 0,1: a ** logBase a b ≈ b"
+    , Binary
+        (\a b ->
+           (not (all veryPositive b) ||
+            not (all nearZero a) ||
+            all (== one) a ||
+            (all (== zero) a && all nearZero (logBase a b)) ||
+            (a ** logBase a b ≈ b))))
+  ]
+
+-- module
+additiveModuleLaws ::
+     (Epsilon a, Epsilon (r a), AdditiveModule r a, Additive (r a)) => [Law2 (r a) a]
+additiveModuleLaws =
+  [ ( "additive module associative: (a + b) .+ c ≈ a + (b .+ c)"
+    , Ternary21 (\a b c -> (a + b) .+ c ≈ a + (b .+ c)))
+  , ( "additive module commutative: (a + b) .+ c ≈ (a .+ c) + b"
+    , Ternary21 (\a b c -> (a + b) .+ c ≈ (a .+ c) + b))
+  , ("additive module unital: a .+ zero == a", Unary10 (\a -> a .+ zero == a))
+  , ( "module additive equivalence: a .+ b ≈ b +. a"
+    , Binary11 (\a b -> a .+ b ≈ b +. a))
+  ]
+
+additiveGroupModuleLaws ::
+     (Epsilon a, Epsilon (r a), AdditiveGroupModule r a, Additive (r a))
+  => [Law2 (r a) a]
+additiveGroupModuleLaws =
+  [ ( "additive group module associative: (a + b) .- c ≈ a + (b .- c)"
+    , Ternary21 (\a b c -> (a + b) .- c ≈ a + (b .- c)))
+  , ( "additive group module commutative: (a + b) .- c ≈ (a .- c) + b"
+    , Ternary21 (\a b c -> (a + b) .- c ≈ (a .- c) + b))
+  , ( "additive group module unital: a .- zero == a"
+    , Unary10 (\a -> a .- zero == a))
+  , ( "module additive group equivalence: a .- b ≈ negate b +. a"
+    , Binary11 (\a b -> a .- b ≈ negate b +. a))
+  ]
+
+multiplicativeModuleLaws ::
+     (Epsilon a, Epsilon (r a), MultiplicativeModule r a, Additive (r a))
+  => [Law2 (r a) a]
+multiplicativeModuleLaws =
+  [ ( "multiplicative module unital: a .* one == a"
+    , Unary10 (\a -> a .* one == a))
+  , ( "module right distribution: (a + b) .* c ≈ (a .* c) + (b .* c)"
+    , Ternary21 (\a b c -> (a + b) .* c ≈ (a .* c) + (b .* c)))
+  , ( "module left distribution: c *. (a + b) ≈ (c *. a) + (c *. b)"
+    , Ternary21 (\a b c -> c *. (a + b) ≈ (c *. a) + (c *. b)))
+  , ("annihilation: a .* zero == zero", Unary10 (\a -> a .* zero == zero))
+  , ( "module multiplicative equivalence: a .* b ≈ b *. a"
+    , Binary11 (\a b -> a .* b ≈ b *. a))
+  ]
+
+multiplicativeGroupModuleLawsFail ::
+     ( Epsilon a
+     , Epsilon (r a)
+     , MultiplicativeGroupModule r a
+     )
+  => [Law2 (r a) a]
+multiplicativeGroupModuleLawsFail =
+  [ ( "multiplicative group module unital: a ./ one == a"
+    , Unary10 (\a -> nearZero a || a ./ one == a))
+  , ( "module multiplicative group equivalence: a ./ b ≈ recip b *. a"
+    , Binary11 (\a b -> b == zero || a ./ b ≈ recip b *. a))
+  ]
+
+banachLaws ::
+     ( Foldable r
+     , Epsilon (r a)
+     , Banach r a
+     , Singleton r
+     , Signed a
+     , FromRatio a
+     , Ord a
+     )
+  => [Law2 (r a) a]
+banachLaws =
+  [ ( "L1: normalize a .* norm a ≈ one"
+    , Unary10
+        (\a ->
+           a == singleton zero ||
+           (any ((> smallRational) . abs) a || (normalizeL1 a .* normL1 a) ≈ a)))
+    , ( "L2: normalize a .* norm a ≈ one"
+    , Unary10
+        (\a ->
+           a == singleton zero ||
+           (any ((> smallRational) . abs) a || (normalizeL2 a .* normL2 a) ≈ a)))
+{-
+    , ( "Lp: normalizeLp a p .* normLp a p ≈ one"
+    , Binary11
+        (\a p ->
+           a == singleton zero ||
+           (any ((> smallRational) . normL1) a || (normalizeLp p a .* normLp p a) ≈ a)))
+-}
+  ]
+
+hilbertLaws ::
+    ( MultiplicativeModule r a
+    , Epsilon a
+    , Epsilon (r a)
+    , Hilbert r a
+    , Additive (r a))
+  => [Law2 (r a) a]
+hilbertLaws =
+  [ ("commutative a <.> b ≈ b <.> a", Ternary21 (\a b _ -> a <.> b ≈ b <.> a))
+  , ( "distributive over addition a <.> (b + c) == a <.> b + a <.> c"
+    , Ternary30 (\a b c -> a <.> (b + c) ≈ a <.> b + a <.> c))
+  , ( "bilinear a <.> (s *. b + c) == s * (a <.> b) + a <.> c"
+    , Quad31 (\a b c s -> a <.> (s *. b + c) == s * (a <.> b) + a <.> c))
+  , ( "scalar multiplication (s0 *. a) <.> (s1 *. b) == s0 * s1 * (a <.> b)"
+    , Quad22 (\a b s0 s1 -> (s0 *. a) <.> (s1 *. b) == s0 * s1 * (a <.> b)))
+  ]
+
+tensorProductLaws ::
+     ( Eq (r (r a))
+     , Additive (r (r a))
+     , TensorProduct (r a)
+     , Epsilon (r a)
+     , Additive (r a)
+     )
+  => [Law2 (r a) a]
+tensorProductLaws =
+  [ ( "left distribution over addition a><b + c><b == (a+c) >< b"
+    , Ternary30 (\a b c -> a >< b + c >< b == (a + c) >< b))
+  , ( "right distribution over addition a><b + a><c == a >< (b+c)"
+    , Ternary30 (\a b c -> a >< b + a >< c == a >< (b + c)))
+  -- , ( "left module tensor correspondance a *. (b><c) == (a><b) .* c"
+  --   , Ternary30 (\a b c -> a *. (b><c) == (a><b) .* c))
+  -- , ( "right module tensor correspondance (a><b) .* c == a *. (b><c)"
+  --   , Ternary30 (\a b c -> (a><b) .* c == a *. (b><c)))
+  ]
+
+-- basis
+additiveBasisLaws :: (Epsilon (r a), AdditiveBasis r a) => [Law (r a)]
+additiveBasisLaws =
+  [ ( "associative: (a .+. b) .+. c ≈ a .+. (b .+. c)"
+    , Ternary (\a b c -> (a .+. b) .+. c ≈ a .+. (b .+. c)))
+  , ("left id: zero .+. a = a", Unary (\a -> zero .+. a == a))
+  , ("right id: a .+. zero = a", Unary (\a -> a .+. zero == a))
+  , ("commutative: a .+. b == b .+. a", Binary (\a b -> a .+. b == b .+. a))
+  ]
+
+additiveGroupBasisLaws :: (Eq (r a), Singleton r, AdditiveGroupBasis r a) => [Law (r a)]
+additiveGroupBasisLaws =
+  [ ( "minus: a .-. a = singleton zero"
+    , Unary (\a -> (a .-. a) == singleton zero))
+  ]
+
+multiplicativeBasisLaws :: (Eq (r a), Singleton r, MultiplicativeBasis r a) => [Law (r a)]
+multiplicativeBasisLaws =
+  [ ( "associative: (a .*. b) .*. c == a .*. (b .*. c)"
+    , Ternary (\a b c -> (a .*. b) .*. c == a .*. (b .*. c)))
+  , ("left id: singleton one .*. a = a", Unary (\a -> singleton one .*. a == a))
+  , ( "right id: a .*. singleton one = a"
+    , Unary (\a -> a .*. singleton one == a))
+  , ("commutative: a .*. b == b .*. a", Binary (\a b -> a .*. b == b .*. a))
+  ]
+
+multiplicativeGroupBasisLaws ::
+     ( Epsilon a
+     , Epsilon (r a)
+     , Singleton r
+     , MultiplicativeGroupBasis r a
+     )
+  => [Law (r a)]
+multiplicativeGroupBasisLaws =
+  [ ( "basis divide: a ./. a ≈ singleton one"
+    , Unary (\a -> a == singleton zero || (a ./. a) ≈ singleton one))
+  ]
+
+-- | semiring
+semiringLaws :: (Epsilon a, Semiring a) => [Law a]
+semiringLaws = additiveLaws <> distributionLaws <>
+    [ ( "associative: (a * b) * c = a * (b * c)"
+    , Ternary (\a b c -> (a `times` b) `times` c == a `times` (b `times` c)))
+    , ("left id: one * a = a", Unary (\a -> one `times` a == a))
+    , ("right id: a * one = a", Unary (\a -> a `times` one == a))
+    ]
+
+-- | ring
+ringLaws :: (Epsilon a, Ring a) => [Law a]
+ringLaws = semiringLaws <> additiveGroupLaws
+
+-- | starsemiring
+starSemiringLaws :: (Epsilon a, StarSemiring a) => [Law a]
+starSemiringLaws = semiringLaws <>
+    [ ( "star law: star a == one + a `times` star a"
+    , Unary (\a -> star a == one + a `times` star a))
+    ]
+
+-- | involutive ring
+involutiveRingLaws :: forall a. (Eq a, MultiplicativeUnital a,InvolutiveRing a) => [Law a]
+involutiveRingLaws =
+    [ ( "adjoint plus law: adj (a + b) ==> adj a + adj b"
+    , Binary (\a b -> adj (a `plus` b) == adj a `plus` adj b))
+    , ( "adjoint times law: adj (a * b) ==> adj b * adj a"
+    , Binary (\a b -> adj (a `times` b) == adj b `times` adj a))
+    , ( "adjoint multiplicative unit law: adj one ==> one"
+    , Nonary (adj (one :: a) == one))
+    , ( "adjoint own inverse law: adj (adj a) ==> a"
+    , Unary (\a -> adj (adj a) == a))
+    ]
+
+
+-- integrals are the law groups that apply to Integral-like numbers
+integralsLaws :: (Eq a, AdditiveGroup a, Integral a, Signed a, ToInteger a, FromInteger a, Multiplicative a) => [Law a]
+integralsLaws =
+  additiveLaws <>
+  additiveGroupLaws <>
+  multiplicativeLaws <>
+  distributionLaws <>
+  integralLaws <>
+  signedLaws
+
+
diff --git a/stack.yaml b/stack.yaml
new file mode 100644
--- /dev/null
+++ b/stack.yaml
@@ -0,0 +1,8 @@
+resolver: nightly-2018-05-06
+
+packages:
+  - .
+  - ../numhask
+  - ../numhask-prelude
+
+extra-deps: []
diff --git a/test/test.hs b/test/test.hs
new file mode 100644
--- /dev/null
+++ b/test/test.hs
@@ -0,0 +1,351 @@
+{-# LANGUAGE TypeSynonymInstances #-}
+{-# LANGUAGE FlexibleInstances #-}
+{-# OPTIONS_GHC -Wall #-}
+{-# OPTIONS_GHC -fno-warn-orphans #-}
+
+-- | testing IEEE numbers is a special kind of hell, and one that I reserve for days when I can hardly think, so please forgive the horrible hackery contained within this file.
+--
+-- This suite sometimes fails, having been hand-crafty towards balancing reasonably approximate equality versus unbounded failure (given enough trials).
+module Main where
+
+import NumHask.Prelude
+import NumHask.Laws
+
+import Test.Tasty (TestTree, defaultMain, testGroup)
+
+import Test.QuickCheck.Arbitrary
+import Test.QuickCheck.Gen
+
+instance Arbitrary Natural where
+  arbitrary = fromInteger . abs <$> arbitrary
+
+instance Arbitrary Rational where
+  arbitrary = reduce <$> (fromInteger <$> arbitrary) <*> (fromInteger <$> arbitrary `suchThat` (>zero))
+
+instance (Signed a, Arbitrary a, ExpField a) => Arbitrary (LogField a) where
+  arbitrary = logField . abs <$> arbitrary
+
+main :: IO ()
+main = defaultMain tests
+
+tests :: TestTree
+tests =
+  testGroup
+    "NumHask"
+    [ testsInt
+    , testsInt8
+    , testsInt16
+    , testsInt32
+    , testsInt64
+    , testsWord
+    , testsWord8
+    , testsWord16
+    , testsWord32
+    , testsWord64
+    , testsNatural
+    , testsFloat
+    , testsDouble
+    , testsBool
+    , testsComplexFloat
+    , testsRational
+    , testsLogFieldDouble
+    ]
+
+testsInt :: TestTree
+testsInt =
+  testGroup
+    "Int"
+    [ testGroup "Additive" $ testLawOf ([] :: [Int]) <$> additiveLaws
+    , testGroup "Additive Group" $ testLawOf ([] :: [Int]) <$> additiveGroupLaws
+    , testGroup "Multiplicative" $
+      testLawOf ([] :: [Int]) <$> multiplicativeLaws
+    , testGroup "Distribution" $ testLawOf ([] :: [Int]) <$> distributionLaws
+    , testGroup "Integral" $ testLawOf ([] :: [Int]) <$> integralLaws
+    , testGroup "Signed" $ testLawOf ([] :: [Int]) <$> signedLaws
+    , testGroup "Metric" $ testLawOf2 ([] :: [(Int, Int)]) <$>
+      metricIntegralLaws
+    , testGroup "Normed or maxBound" $ testLawOf2 ([] :: [(Int, Int)]) <$> normedBoundedLaws
+    ]
+
+testsInteger :: TestTree
+testsInteger =
+  testGroup
+    "Integer"
+    [ testGroup "Integrals" $ testLawOf ([] :: [Integer]) <$> integralsLaws
+    , testGroup "Metric" $ testLawOf2 ([] :: [(Integer, Integer)]) <$>
+      metricIntegralLaws
+    , testGroup "Normed" $ testLawOf2 ([] :: [(Integer, Integer)]) <$> normedLaws
+    ]
+
+testsInt8 :: TestTree
+testsInt8 =
+  testGroup
+    "Int8"
+    [ testGroup "Integrals" $ testLawOf ([] :: [Int8]) <$> integralsLaws
+    , testGroup "Metric" $ testLawOf2 ([] :: [(Int8, Int8)]) <$>
+      metricIntegralBoundedLaws
+    , testGroup "Normed or maxBound" $ testLawOf2 ([] :: [(Int8, Int8)]) <$>
+      normedBoundedLaws
+    ]
+
+testsInt16 :: TestTree
+testsInt16 =
+  testGroup
+    "Int16"
+    [ testGroup "Integrals" $ testLawOf ([] :: [Int16]) <$> integralsLaws
+    , testGroup "Metric" $ testLawOf2 ([] :: [(Int16, Int16)]) <$>
+      metricIntegralBoundedLaws
+    , testGroup "Normed or maxBound" $ testLawOf2 ([] :: [(Int16, Int16)]) <$>
+      normedBoundedLaws
+    ]
+
+testsInt32 :: TestTree
+testsInt32 =
+  testGroup
+    "Int32"
+    [ testGroup "Integrals" $ testLawOf ([] :: [Int32]) <$> integralsLaws
+    , testGroup "Metric" $ testLawOf2 ([] :: [(Int32, Int32)]) <$>
+      metricIntegralBoundedLaws
+    , testGroup "Normed or maxBound" $ testLawOf2 ([] :: [(Int32, Int32)]) <$>
+      normedBoundedLaws
+    ]
+
+testsInt64 :: TestTree
+testsInt64 =
+  testGroup
+    "Int64"
+    [ testGroup "Integrals" $ testLawOf ([] :: [Int64]) <$> integralsLaws
+    , testGroup "Metric" $ testLawOf2 ([] :: [(Int64, Int64)]) <$>
+      metricIntegralBoundedLaws
+    , testGroup "Normed or maxBound" $ testLawOf2 ([] :: [(Int64, Int64)]) <$>
+      normedBoundedLaws
+    ]
+
+testsWord :: TestTree
+testsWord =
+  testGroup
+    "Word"
+    [ testGroup "Additive" $ testLawOf ([] :: [Word]) <$> additiveLaws
+    , testGroup "Multiplicative" $
+      testLawOf ([] :: [Word]) <$> multiplicativeLaws
+    , testGroup "Distribution" $ testLawOf ([] :: [Word]) <$> distributionLaws
+    , testGroup "Integral" $ testLawOf ([] :: [Word]) <$> integralLaws
+    , testGroup "Signed" $ testLawOf ([] :: [Word]) <$> signedLaws
+    , testGroup "Metric" $ testLawOf2 ([] :: [(Word, Word)]) <$>
+      metricIntegralBoundedLaws
+    , testGroup "Normed or maxBound" $ testLawOf2 ([] :: [(Word, Word)]) <$>
+      normedBoundedLaws
+    ]
+
+testsWord8 :: TestTree
+testsWord8 =
+  testGroup
+    "Word8"
+    [ testGroup "Additive" $ testLawOf ([] :: [Word8]) <$> additiveLaws
+    , testGroup "Multiplicative" $
+      testLawOf ([] :: [Word8]) <$> multiplicativeLaws
+    , testGroup "Distribution" $ testLawOf ([] :: [Word8]) <$> distributionLaws
+    , testGroup "Integral" $ testLawOf ([] :: [Word8]) <$> integralLaws
+    , testGroup "Signed" $ testLawOf ([] :: [Word8]) <$> signedLaws
+    , testGroup "Metric" $ testLawOf2 ([] :: [(Word8, Word8)]) <$>
+      metricIntegralBoundedLaws
+    , testGroup "Normed or maxBound" $ testLawOf2 ([] :: [(Word8, Word8)]) <$>
+      normedBoundedLaws
+    ]
+
+testsWord16 :: TestTree
+testsWord16 =
+  testGroup
+    "Word16"
+    [ testGroup "Additive" $ testLawOf ([] :: [Word16]) <$> additiveLaws
+    , testGroup "Multiplicative" $
+      testLawOf ([] :: [Word16]) <$> multiplicativeLaws
+    , testGroup "Distribution" $ testLawOf ([] :: [Word16]) <$> distributionLaws
+    , testGroup "Integral" $ testLawOf ([] :: [Word16]) <$> integralLaws
+    , testGroup "Signed" $ testLawOf ([] :: [Word16]) <$> signedLaws
+    , testGroup "Metric" $ testLawOf2 ([] :: [(Word16, Word16)]) <$>
+      metricIntegralBoundedLaws
+    , testGroup "Normed or maxBound" $ testLawOf2 ([] :: [(Word16, Word16)]) <$>
+      normedBoundedLaws
+    ]
+
+testsWord32 :: TestTree
+testsWord32 =
+  testGroup
+    "Word32"
+    [ testGroup "Additive" $ testLawOf ([] :: [Word32]) <$> additiveLaws
+    , testGroup "Multiplicative" $
+      testLawOf ([] :: [Word32]) <$> multiplicativeLaws
+    , testGroup "Distribution" $ testLawOf ([] :: [Word32]) <$> distributionLaws
+    , testGroup "Integral" $ testLawOf ([] :: [Word32]) <$> integralLaws
+    , testGroup "Signed" $ testLawOf ([] :: [Word32]) <$> signedLaws
+    , testGroup "Metric" $ testLawOf2 ([] :: [(Word32, Word32)]) <$>
+      metricIntegralBoundedLaws
+    , testGroup "Normed or maxBound" $ testLawOf2 ([] :: [(Word32, Word32)]) <$>
+      normedBoundedLaws
+    ]
+
+testsWord64 :: TestTree
+testsWord64 =
+  testGroup
+    "Word64"
+    [ testGroup "Additive" $ testLawOf ([] :: [Word64]) <$> additiveLaws
+    , testGroup "Multiplicative" $
+      testLawOf ([] :: [Word64]) <$> multiplicativeLaws
+    , testGroup "Distribution" $ testLawOf ([] :: [Word64]) <$> distributionLaws
+    , testGroup "Integral" $ testLawOf ([] :: [Word64]) <$> integralLaws
+    , testGroup "Signed" $ testLawOf ([] :: [Word64]) <$> signedLaws
+    , testGroup "Metric" $ testLawOf2 ([] :: [(Word64, Word64)]) <$>
+      metricIntegralBoundedLaws
+    , testGroup "Normed or maxBound" $ testLawOf2 ([] :: [(Word64, Word64)]) <$>
+      normedBoundedLaws
+    ]
+
+testsNatural :: TestTree
+testsNatural =
+  testGroup
+    "Natural"
+    [ testGroup "Additive" $ testLawOf ([] :: [Natural]) <$> additiveLaws
+    , testGroup "Multiplicative" $
+      testLawOf ([] :: [Natural]) <$> multiplicativeLaws
+    , testGroup "Distribution" $ testLawOf ([] :: [Natural]) <$> distributionLaws
+    , testGroup "Naturalegral" $ testLawOf ([] :: [Natural]) <$> integralLaws
+    , testGroup "Signed" $ testLawOf ([] :: [Natural]) <$> signedLaws
+    , testGroup "Normed" $ testLawOf2 ([] :: [(Natural, Natural)]) <$> normedLaws
+    ]
+
+testsFloat :: TestTree
+testsFloat =
+  testGroup
+    "Float"
+    [ testGroup "Additive - Associative Fail" $
+      testLawOf ([] :: [Float]) <$> additiveLawsFail
+    , testGroup "Additive Group" $
+      testLawOf ([] :: [Float]) <$> additiveGroupLaws
+    , testGroup "Multiplicative - Associative Fail" $
+      testLawOf ([] :: [Float]) <$> multiplicativeLawsFail
+    , testGroup "MultiplicativeGroup" $
+      testLawOf ([] :: [Float]) <$> multiplicativeGroupLaws_
+    , testGroup "Distribution - Fail" $
+      testLawOf ([] :: [Float]) <$> distributionLawsFail
+    , testGroup "Signed" $ testLawOf ([] :: [Float]) <$> signedLaws
+    , testGroup "Normed" $ testLawOf2 ([] :: [(Float, Float)]) <$> normedLaws
+    , testGroup "Metric" $ testLawOf2 ([] :: [(Float, Float)]) <$> metricRationalLaws
+    , testGroup "Upper Bounded Field" $
+      testLawOf ([] :: [Float]) <$> upperBoundedFieldLaws
+    , testGroup "Lower Bounded Field" $
+      testLawOf ([] :: [Float]) <$> lowerBoundedFieldLaws
+    , testGroup "Quotient Field" $
+      testLawOf2 ([] :: [(Float,Integer)]) <$> quotientFieldLaws
+    , testGroup "Exponential Field" $ testLawOf2 ([] :: [(Float,Float)]) <$> expFieldLaws
+    , testGroup "Rational" $ testLawOf ([] :: [Float]) <$> rationalLaws
+    ]
+
+testsDouble :: TestTree
+testsDouble =
+  testGroup
+    "Double"
+    [ testGroup "Additive - Associative Fail" $
+      testLawOf ([] :: [Double]) <$> additiveLawsFail
+    , testGroup "Additive Group" $
+      testLawOf ([] :: [Double]) <$> additiveGroupLaws
+    , testGroup "Multiplicative - Associative Fail" $
+      testLawOf ([] :: [Double]) <$> multiplicativeLawsFail
+    , testGroup "MultiplicativeGroup" $
+      testLawOf ([] :: [Double]) <$> multiplicativeGroupLaws_
+    , testGroup "Distribution - Fail" $
+      testLawOf ([] :: [Double]) <$> distributionLawsFail
+    , testGroup "Signed" $ testLawOf ([] :: [Double]) <$> signedLaws
+    , testGroup "Normed" $ testLawOf2 ([] :: [(Double, Double)]) <$> normedLaws
+    , testGroup "Metric" $ testLawOf2 ([] :: [(Double, Double)]) <$> metricRationalLaws
+    , testGroup "Upper Bounded Field" $
+      testLawOf ([] :: [Double]) <$> upperBoundedFieldLaws
+    , testGroup "Lower Bounded Field" $
+      testLawOf ([] :: [Double]) <$> lowerBoundedFieldLaws
+    , testGroup "Quotient Field" $
+      testLawOf2 ([] :: [(Double,Integer)]) <$> quotientFieldLaws
+    , testGroup "Exponential Field" $ testLawOf2 ([] :: [(Double,Double)]) <$> expFieldLaws
+    , testGroup "Rational" $ testLawOf ([] :: [Double]) <$> rationalLaws
+    ]
+
+testsBool :: TestTree
+testsBool =
+  testGroup
+    "Bool"
+    [ testGroup "Idempotent" $ testLawOf ([] :: [Bool]) <$> idempotentLaws
+    , testGroup "Additive" $ testLawOf ([] :: [Bool]) <$> additiveLaws
+    , testGroup "Multiplicative" $
+      testLawOf ([] :: [Bool]) <$> multiplicativeLaws
+    , testGroup "Distribution" $ testLawOf ([] :: [Bool]) <$> distributionLaws
+    ]
+
+testsComplexFloat :: TestTree
+testsComplexFloat =
+  testGroup
+    "Complex Float"
+    [ testGroup "Additive - Associative Fail" $
+      testLawOf ([] :: [Complex Float]) <$> additiveLawsFail
+    , testGroup "Additive Group" $
+      testLawOf ([] :: [Complex Float]) <$> additiveGroupLaws
+    , testGroup "Multiplicative - Associative Fail" $
+      testLawOf ([] :: [Complex Float]) <$> multiplicativeLawsFail
+    , testGroup "MultiplicativeGroup" $
+      testLawOf ([] :: [Complex Float]) <$> multiplicativeGroupLaws_
+    , testGroup "Distribution - Fail" $
+      testLawOf ([] :: [Complex Float]) <$> distributionLawsFail
+    -- , testGroup "Exponential Field" $
+    --   testLawOf2 ([] :: [(Complex Float, Float)]) <$> expFieldLaws 
+    , testGroup "Normed" $ testLawOf2 ([] :: [(Complex Float, Float)]) <$>
+      normedLaws
+    , testGroup "Metric" $ testLawOf2 ([] :: [(Complex Float, Float)]) <$>
+      metricRationalLaws
+    , testGroup "Involutive Ring" $ testLawOf ([] :: [Complex Float]) <$>
+      involutiveRingLaws
+    ]
+
+testsRational :: TestTree
+testsRational =
+  testGroup
+    "Rational"
+    [ testGroup "Additive - Associative" $
+      testLawOf ([] :: [Rational]) <$> additiveLaws
+    , testGroup "Additive Group" $
+      testLawOf ([] :: [Rational]) <$> additiveGroupLaws
+    , testGroup "Multiplicative - Associative" $
+      testLawOf ([] :: [Rational]) <$> multiplicativeLaws
+    , testGroup "MultiplicativeGroup" $
+      testLawOf ([] :: [Rational]) <$> multiplicativeGroupLaws_
+    , testGroup "Distribution" $
+      testLawOf ([] :: [Rational]) <$> distributionLaws
+    , testGroup "Signed" $ testLawOf ([] :: [Rational]) <$> signedLaws
+    , testGroup "Normed" $ testLawOf2 ([] :: [(Rational, Rational)]) <$> normedLaws
+    , testGroup "Metric" $ testLawOf2 ([] :: [(Rational, Rational)]) <$> metricRationalLaws
+    , testGroup "Rational" $ testLawOf ([] :: [Rational]) <$> rationalLaws
+
+    -- fixme: rounding and infinities need work
+
+    , testGroup "Quotient Field" $ testLawOf2 ([] :: [(Rational, Integer)]) <$> quotientFieldLaws
+    , testGroup "Upper Bounded Field" $ testLawOf ([] :: [Rational]) <$> upperBoundedFieldLaws
+    , testGroup "Lower Bounded Field" $ testLawOf ([] :: [Rational]) <$> lowerBoundedFieldLaws
+
+
+    ]
+
+    --  testGroup "Distribution" $ testLawOf ([] :: [Int]) <$> distributionLaws
+    -- , testGroup "Metric" $ testLawOf2 ([] :: [(Int, Int)]) <$>
+    --   metricIntegralLaws
+    -- , testGroup "Normed or maxBound" $ testLawOf2 ([] :: [(Int, Int)]) <$> normedBoundedLaws
+
+testsLogFieldDouble :: TestTree
+testsLogFieldDouble =
+  testGroup
+    "LogField Double"
+    [ testGroup "Additive - Associative Fail" $
+      testLawOf ([] :: [LogField Double]) <$> additiveLawsFail
+    , testGroup "Multiplicative - Associative Fail" $
+      testLawOf ([] :: [LogField Double]) <$> multiplicativeLawsFail
+    , testGroup "MultiplicativeGroup" $
+      testLawOf ([] :: [LogField Double]) <$> multiplicativeGroupLaws_
+    , testGroup "Distribution - Fail" $
+      testLawOf ([] :: [LogField Double]) <$> distributionLawsFail
+    ]
