diff --git a/build.sbt b/build.sbt
index 7442f366..a4346598 100644
--- a/build.sbt
+++ b/build.sbt
@@ -7,13 +7,13 @@ import com.typesafe.tools.mima.plugin.MimaPlugin.mimaDefaultSettings
 lazy val scalaCheckVersion = "1.13.4"
 lazy val scalaTestVersion = "3.0.1"
 lazy val disciplineVersion = "0.7.2"
-lazy val catsVersion = "1.0.0-MF"
+lazy val catsVersion = "1.0.0-RC1"
 lazy val catalystsVersion = "0.0.5"
 
 lazy val buildSettings = Seq(
   organization := "org.typelevel",
-  scalaVersion := "2.12.3",
-  crossScalaVersions := Seq("2.10.6", "2.11.11", "2.12.3")
+  scalaVersion := "2.12.4",
+  crossScalaVersions := Seq("2.10.6", "2.11.11", "2.12.4")
 )
 
 lazy val commonSettings = Seq(
diff --git a/laws/src/main/scala/algebra/laws/AdditiveCommutativeGroupLaws.scala b/laws/src/main/scala/algebra/laws/AdditiveCommutativeGroupLaws.scala
new file mode 100644
index 00000000..33c0aaee
--- /dev/null
+++ b/laws/src/main/scala/algebra/laws/AdditiveCommutativeGroupLaws.scala
@@ -0,0 +1,13 @@
+package algebra
+package laws
+
+import algebra.ring._
+
+trait AdditiveCommutativeGroupLaws[A] extends AdditiveGroupLaws[A] with AdditiveCommutativeMonoidLaws[A] {
+  override implicit def S: AdditiveCommutativeGroup[A]
+}
+
+object AdditiveCommutativeGroupLaws {
+  def apply[A](implicit ev: AdditiveCommutativeGroup[A]): AdditiveCommutativeGroupLaws[A] =
+    new AdditiveCommutativeGroupLaws[A] { def S: AdditiveCommutativeGroup[A] = ev }
+}
diff --git a/laws/src/main/scala/algebra/laws/AdditiveCommutativeMonoidLaws.scala b/laws/src/main/scala/algebra/laws/AdditiveCommutativeMonoidLaws.scala
new file mode 100644
index 00000000..2832b653
--- /dev/null
+++ b/laws/src/main/scala/algebra/laws/AdditiveCommutativeMonoidLaws.scala
@@ -0,0 +1,13 @@
+package algebra
+package laws
+
+import algebra.ring._
+
+trait AdditiveCommutativeMonoidLaws[A] extends AdditiveMonoidLaws[A] with AdditiveCommutativeSemigroupLaws[A] {
+  override implicit def S: AdditiveCommutativeMonoid[A]
+}
+
+object AdditiveCommutativeMonoidLaws {
+  def apply[A](implicit ev: AdditiveCommutativeMonoid[A]): AdditiveCommutativeMonoidLaws[A] =
+  new AdditiveCommutativeMonoidLaws[A] { def S: AdditiveCommutativeMonoid[A] = ev }
+}
diff --git a/laws/src/main/scala/algebra/laws/AdditiveCommutativeSemigroupLaws.scala b/laws/src/main/scala/algebra/laws/AdditiveCommutativeSemigroupLaws.scala
new file mode 100644
index 00000000..23250fb4
--- /dev/null
+++ b/laws/src/main/scala/algebra/laws/AdditiveCommutativeSemigroupLaws.scala
@@ -0,0 +1,19 @@
+package algebra
+package laws
+
+import algebra.ring._
+import cats.kernel.laws._
+
+
+trait AdditiveCommutativeSemigroupLaws[A] extends AdditiveSemigroupLaws[A] {
+  override implicit def S: AdditiveCommutativeSemigroup[A]
+
+  def plusCommutative(x: A, y: A): IsEq[A] =
+    S.plus(x, y) <-> S.plus(y, x)
+
+}
+
+object AdditiveCommutativeSemigroupLaws {
+  def apply[A](implicit ev: AdditiveCommutativeSemigroup[A]): AdditiveCommutativeSemigroupLaws[A] =
+    new AdditiveCommutativeSemigroupLaws[A] { def S: AdditiveCommutativeSemigroup[A] = ev }
+}
diff --git a/laws/src/main/scala/algebra/laws/AdditiveGroupLaws.scala b/laws/src/main/scala/algebra/laws/AdditiveGroupLaws.scala
new file mode 100755
index 00000000..cf5c6c84
--- /dev/null
+++ b/laws/src/main/scala/algebra/laws/AdditiveGroupLaws.scala
@@ -0,0 +1,25 @@
+package algebra
+package laws
+
+import algebra.ring._
+import cats.kernel.laws._
+
+
+trait AdditiveGroupLaws[A] extends AdditiveMonoidLaws[A] {
+  override implicit def S: AdditiveGroup[A]
+
+  def leftNegate(x: A): IsEq[A] =
+    S.plus(S.negate(x), x) <-> S.zero
+
+  def rightNegate(x: A): IsEq[A] =
+    S.plus(x, S.negate(x)) <-> S.zero
+
+  def consistentMinus(x: A, y: A): IsEq[A] =
+    S.minus(x, y) <-> S.plus(x, S.negate(y))
+
+}
+
+object AdditiveGroupLaws {
+  def apply[A](implicit ev: AdditiveGroup[A]): AdditiveGroupLaws[A] =
+    new AdditiveGroupLaws[A] { def S: AdditiveGroup[A] = ev }
+}
diff --git a/laws/src/main/scala/algebra/laws/AdditiveMonoidLaws.scala b/laws/src/main/scala/algebra/laws/AdditiveMonoidLaws.scala
new file mode 100755
index 00000000..19aa5c65
--- /dev/null
+++ b/laws/src/main/scala/algebra/laws/AdditiveMonoidLaws.scala
@@ -0,0 +1,29 @@
+package algebra.laws
+
+import algebra.ring._
+import cats.kernel.Eq
+import cats.kernel.laws._
+
+trait AdditiveMonoidLaws[A] extends AdditiveSemigroupLaws[A] {
+  override implicit def S: AdditiveMonoid[A]
+
+  def leftZero(a: A): IsEq[A] =
+    S.plus(S.zero, a) <-> a
+
+  def rightZero(a: A): IsEq[A] =
+    S.plus(a, S.zero) <-> a
+
+  def sumN0(a: A): IsEq[A] =
+    S.sumN(a, 0) <-> S.zero
+
+  def sumAll: IsEq[A] =
+    S.sum(Nil) <-> S.zero
+
+  def isZero(a: A, eqv: Eq[A]): IsEq[Boolean] =
+    eqv.eqv(a, S.zero) <-> S.isZero(a)(eqv)
+}
+
+object AdditiveMonoidLaws {
+  def apply[A](implicit ev: AdditiveMonoid[A]): AdditiveMonoidLaws[A] =
+    new AdditiveMonoidLaws[A] { def S: AdditiveMonoid[A] = ev }
+}
diff --git a/laws/src/main/scala/algebra/laws/AdditiveSemigroupLaws.scala b/laws/src/main/scala/algebra/laws/AdditiveSemigroupLaws.scala
new file mode 100755
index 00000000..b1249c13
--- /dev/null
+++ b/laws/src/main/scala/algebra/laws/AdditiveSemigroupLaws.scala
@@ -0,0 +1,29 @@
+package algebra
+package laws
+
+import algebra.ring._
+import cats.kernel.laws._
+
+trait AdditiveSemigroupLaws[A] {
+  implicit def S: AdditiveSemigroup[A]
+
+  def plusAssociative(x: A, y: A, z: A): IsEq[A] =
+    S.plus(S.plus(x, y), z) <-> S.plus(x, S.plus(y, z))
+
+  def sumN1(a: A): IsEq[A] =
+    S.sumN(a, 1) <-> a
+
+  def sumN2(a: A): IsEq[A] =
+    S.sumN(a, 2) <-> S.plus(a, a)
+
+  def sumN3(a: A): IsEq[A] =
+    S.sumN(a, 3) <-> S.plus(S.plus(a, a), a)
+
+  def trySum(xs: Vector[A]): IsEq[Option[A]] =
+    S.trySum(xs) <-> xs.reduceOption(S.plus)
+}
+
+object AdditiveSemigroupLaws {
+  def apply[A](implicit ev: AdditiveSemigroup[A]): AdditiveSemigroupLaws[A] =
+    new AdditiveSemigroupLaws[A] { def S: AdditiveSemigroup[A] = ev }
+}
diff --git a/laws/src/main/scala/algebra/laws/BoundedDistributiveLatticeLaws.scala b/laws/src/main/scala/algebra/laws/BoundedDistributiveLatticeLaws.scala
new file mode 100644
index 00000000..fcdd3e3b
--- /dev/null
+++ b/laws/src/main/scala/algebra/laws/BoundedDistributiveLatticeLaws.scala
@@ -0,0 +1,13 @@
+package algebra
+package laws
+
+import algebra.lattice._
+
+trait BoundedDistributiveLatticeLaws[A] extends BoundedLatticeLaws[A] with DistributiveLatticeLaws[A] {
+  override implicit def S: BoundedDistributiveLattice[A]
+}
+
+object BoundedDistributiveLatticeLaws {
+  def apply[A](implicit ev: BoundedDistributiveLattice[A]): BoundedDistributiveLatticeLaws[A] =
+    new BoundedDistributiveLatticeLaws[A] { def S: BoundedDistributiveLattice[A] = ev }
+}
diff --git a/laws/src/main/scala/algebra/laws/BoundedJoinLatticeLaws.scala b/laws/src/main/scala/algebra/laws/BoundedJoinLatticeLaws.scala
new file mode 100644
index 00000000..591710b7
--- /dev/null
+++ b/laws/src/main/scala/algebra/laws/BoundedJoinLatticeLaws.scala
@@ -0,0 +1,13 @@
+package algebra
+package laws
+
+import algebra.lattice._
+
+trait BoundedJoinLatticeLaws[A] extends LatticeLaws[A] with BoundedJoinSemilatticeLaws[A] {
+  override implicit def S: Lattice[A] with BoundedJoinSemilattice[A]
+}
+
+object BoundedJoinLatticeLaws {
+  def apply[A](implicit ev: Lattice[A] with BoundedJoinSemilattice[A]): BoundedJoinLatticeLaws[A] =
+    new BoundedJoinLatticeLaws[A] { def S: Lattice[A] with BoundedJoinSemilattice[A] = ev }
+}
diff --git a/laws/src/main/scala/algebra/laws/BoundedJoinSemilatticeLaws.scala b/laws/src/main/scala/algebra/laws/BoundedJoinSemilatticeLaws.scala
new file mode 100644
index 00000000..5d8c15ea
--- /dev/null
+++ b/laws/src/main/scala/algebra/laws/BoundedJoinSemilatticeLaws.scala
@@ -0,0 +1,13 @@
+package algebra.laws
+
+import algebra.lattice._
+import cats.kernel.laws.BoundedSemilatticeLaws
+
+trait BoundedJoinSemilatticeLaws[A] extends JoinSemilatticeLaws[A] with BoundedSemilatticeLaws[A] {
+  override implicit def S: BoundedJoinSemilattice[A]
+}
+
+object BoundedJoinSemilatticeLaws {
+  def apply[A](implicit ev: BoundedJoinSemilattice[A]): BoundedJoinSemilatticeLaws[A] =
+    new BoundedJoinSemilatticeLaws[A] { def S: BoundedJoinSemilattice[A] = ev }
+}
diff --git a/laws/src/main/scala/algebra/laws/BoundedLatticeLaws.scala b/laws/src/main/scala/algebra/laws/BoundedLatticeLaws.scala
new file mode 100644
index 00000000..e859aeb1
--- /dev/null
+++ b/laws/src/main/scala/algebra/laws/BoundedLatticeLaws.scala
@@ -0,0 +1,14 @@
+package algebra
+package laws
+
+import algebra.lattice._
+
+trait BoundedLatticeLaws[A] extends LatticeLaws[A] with BoundedMeetLatticeLaws[A] with BoundedJoinLatticeLaws[A] {
+  override implicit def S: BoundedLattice[A]
+}
+
+object BoundedLatticeLaws {
+  def apply[A](implicit ev: BoundedLattice[A]): BoundedLatticeLaws[A] =
+    new BoundedLatticeLaws[A] { def S: BoundedLattice[A] = ev }
+}
+
diff --git a/laws/src/main/scala/algebra/laws/BoundedMeetLatticeLaws.scala b/laws/src/main/scala/algebra/laws/BoundedMeetLatticeLaws.scala
new file mode 100644
index 00000000..d1e5de86
--- /dev/null
+++ b/laws/src/main/scala/algebra/laws/BoundedMeetLatticeLaws.scala
@@ -0,0 +1,13 @@
+package algebra.laws
+
+import algebra.lattice._
+
+trait BoundedMeetLatticeLaws[A] extends LatticeLaws[A] with BoundedMeetSemilatticeLaws[A] {
+  override implicit def S: Lattice[A] with BoundedMeetSemilattice[A]
+}
+
+object BoundedMeetLatticeLaws {
+  def apply[A](implicit ev: Lattice[A] with BoundedMeetSemilattice[A]): BoundedMeetLatticeLaws[A] =
+    new BoundedMeetLatticeLaws[A] { def S: Lattice[A] with BoundedMeetSemilattice[A] = ev }
+}
+
diff --git a/laws/src/main/scala/algebra/laws/BoundedMeetSemilatticeLaws.scala b/laws/src/main/scala/algebra/laws/BoundedMeetSemilatticeLaws.scala
new file mode 100644
index 00000000..6a9decbb
--- /dev/null
+++ b/laws/src/main/scala/algebra/laws/BoundedMeetSemilatticeLaws.scala
@@ -0,0 +1,13 @@
+package algebra.laws
+
+import cats.kernel.laws.BoundedSemilatticeLaws
+import algebra.lattice._
+
+trait BoundedMeetSemilatticeLaws[A] extends MeetSemilatticeLaws[A] with BoundedSemilatticeLaws[A] {
+  override implicit def S: BoundedMeetSemilattice[A]
+}
+
+object BoundedMeetSemilatticeLaws {
+  def apply[A](implicit ev: BoundedMeetSemilattice[A]): BoundedMeetSemilatticeLaws[A] =
+    new BoundedMeetSemilatticeLaws[A] { def S: BoundedMeetSemilattice[A] = ev }
+}
diff --git a/laws/src/main/scala/algebra/laws/CheckSupport.scala b/laws/src/main/scala/algebra/laws/CheckSupport.scala
deleted file mode 100644
index 64b0ccd1..00000000
--- a/laws/src/main/scala/algebra/laws/CheckSupport.scala
+++ /dev/null
@@ -1,12 +0,0 @@
-package algebra.laws
-
-/**
- * This object contains Arbitrary instances for types defined in
- * algebra.instances, as well as anything else we'd like to import to assist
- * in running ScalaCheck tests.
- *
- * (Since algebra-instances has no dependencies, its types can't
- * define Arbitrary instances in companions.)
- */
-object CheckSupport {
-}
diff --git a/laws/src/main/scala/algebra/laws/CommutativeRigLaws.scala b/laws/src/main/scala/algebra/laws/CommutativeRigLaws.scala
new file mode 100755
index 00000000..2385e189
--- /dev/null
+++ b/laws/src/main/scala/algebra/laws/CommutativeRigLaws.scala
@@ -0,0 +1,13 @@
+package algebra
+package laws
+
+import algebra.ring._
+
+trait CommutativeRigLaws[A] extends RigLaws[A] with CommutativeSemiringLaws[A] with MultiplicativeCommutativeMonoidLaws[A] {
+  override implicit def S: CommutativeRig[A]
+}
+
+object CommutativeRigLaws {
+  def apply[A](implicit ev: CommutativeRig[A]): CommutativeRigLaws[A] =
+    new CommutativeRigLaws[A] { def S: CommutativeRig[A] = ev }
+}
diff --git a/laws/src/main/scala/algebra/laws/CommutativeRingLaws.scala b/laws/src/main/scala/algebra/laws/CommutativeRingLaws.scala
new file mode 100755
index 00000000..bb711887
--- /dev/null
+++ b/laws/src/main/scala/algebra/laws/CommutativeRingLaws.scala
@@ -0,0 +1,13 @@
+package algebra
+package laws
+
+import algebra.ring._
+
+trait CommutativeRingLaws[A] extends RingLaws[A] with CommutativeRigLaws[A] with CommutativeRngLaws[A] {
+  override implicit def S: CommutativeRing[A]
+}
+
+object CommutativeRingLaws {
+  def apply[A](implicit ev: CommutativeRing[A]): CommutativeRingLaws[A] =
+    new CommutativeRingLaws[A] { def S: CommutativeRing[A] = ev }
+}
diff --git a/laws/src/main/scala/algebra/laws/CommutativeRngLaws.scala b/laws/src/main/scala/algebra/laws/CommutativeRngLaws.scala
new file mode 100755
index 00000000..aa91f4a0
--- /dev/null
+++ b/laws/src/main/scala/algebra/laws/CommutativeRngLaws.scala
@@ -0,0 +1,13 @@
+package algebra
+package laws
+
+import algebra.ring._
+
+trait CommutativeRngLaws[A] extends CommutativeSemiringLaws[A] with RngLaws[A] {
+  override implicit def S: CommutativeRng[A]
+}
+
+object CommutativeRngLaws {
+  def apply[A](implicit ev: CommutativeRng[A]): CommutativeRngLaws[A] =
+    new CommutativeRngLaws[A] { def S: CommutativeRng[A] = ev }
+}
diff --git a/laws/src/main/scala/algebra/laws/CommutativeSemiringLaws.scala b/laws/src/main/scala/algebra/laws/CommutativeSemiringLaws.scala
new file mode 100755
index 00000000..9415eea0
--- /dev/null
+++ b/laws/src/main/scala/algebra/laws/CommutativeSemiringLaws.scala
@@ -0,0 +1,13 @@
+package algebra
+package laws
+
+import algebra.ring._
+
+trait CommutativeSemiringLaws[A] extends SemiringLaws[A] with MultiplicativeCommutativeSemigroupLaws[A] {
+  override implicit def S: CommutativeSemiring[A]
+}
+
+object CommutativeSemiringLaws {
+  def apply[A](implicit ev: CommutativeSemiring[A]): CommutativeSemiringLaws[A] =
+    new CommutativeSemiringLaws[A] { def S: CommutativeSemiring[A] = ev }
+}
diff --git a/laws/src/main/scala/algebra/laws/DistributiveLatticeLaws.scala b/laws/src/main/scala/algebra/laws/DistributiveLatticeLaws.scala
new file mode 100644
index 00000000..4c312d46
--- /dev/null
+++ b/laws/src/main/scala/algebra/laws/DistributiveLatticeLaws.scala
@@ -0,0 +1,20 @@
+package algebra
+package laws
+
+import algebra.lattice._
+import cats.kernel.laws._
+
+
+trait DistributiveLatticeLaws[A] extends LatticeLaws[A] {
+  override implicit def S: DistributiveLattice[A]
+
+  def distributive(x: A, y: A, z: A)(implicit E: Eq[A]): IsEq[Boolean] =
+    (E.eqv(S.join(x, S.meet(y, z)), S.meet(S.join(x, y), S.join(x, z))) &&
+      E.eqv(S.meet(x, S.join(y, z)), S.join(S.meet(x, y), S.meet(x, z)))) <-> true
+
+}
+
+object DistributiveLatticeLaws {
+  def apply[A](implicit ev: DistributiveLattice[A]): DistributiveLatticeLaws[A] =
+    new DistributiveLatticeLaws[A] { def S: DistributiveLattice[A] = ev }
+}
diff --git a/laws/src/main/scala/algebra/laws/FieldLaws.scala b/laws/src/main/scala/algebra/laws/FieldLaws.scala
new file mode 100755
index 00000000..9c0757ca
--- /dev/null
+++ b/laws/src/main/scala/algebra/laws/FieldLaws.scala
@@ -0,0 +1,13 @@
+package algebra
+package laws
+
+import algebra.ring._
+
+trait FieldLaws[A] extends CommutativeRingLaws[A] with MultiplicativeCommutativeGroupLaws[A] {
+  override implicit def S: Field[A]
+}
+
+object FieldLaws {
+  def apply[A: Field]: FieldLaws[A] =
+    new FieldLaws[A] { def S: Field[A] = implicitly }
+}
diff --git a/laws/src/main/scala/algebra/laws/HeytingLaws.scala b/laws/src/main/scala/algebra/laws/HeytingLaws.scala
new file mode 100644
index 00000000..4da36142
--- /dev/null
+++ b/laws/src/main/scala/algebra/laws/HeytingLaws.scala
@@ -0,0 +1,19 @@
+package algebra.laws
+
+import algebra._
+import algebra.lattice._
+
+import cats.kernel.laws._
+
+
+trait HeytingLaws[A] extends BoundedDistributiveLatticeLaws[A] {
+  override implicit def S: Heyting[A]
+
+  def absorption(x: A, y: A)(implicit E: Eq[A]): IsEq[Boolean] =
+    (E.eqv(S.join(x, S.meet(x, y)), x) && E.eqv(S.meet(x, S.join(x, y)), x)) <-> true
+}
+
+object HeytingLaws {
+  def apply[A](implicit ev: Heyting[A]): HeytingLaws[A] =
+    new HeytingLaws[A] { def S: Heyting[A] = ev }
+}
diff --git a/laws/src/main/scala/algebra/laws/JoinSemilatticeLaws.scala b/laws/src/main/scala/algebra/laws/JoinSemilatticeLaws.scala
new file mode 100644
index 00000000..de08b8b8
--- /dev/null
+++ b/laws/src/main/scala/algebra/laws/JoinSemilatticeLaws.scala
@@ -0,0 +1,13 @@
+package algebra.laws
+
+import algebra.lattice.JoinSemilattice
+import cats.kernel.laws.SemilatticeLaws
+
+trait JoinSemilatticeLaws[A] extends SemilatticeLaws[A] {
+  override implicit def S: JoinSemilattice[A]
+}
+
+object JoinSemilatticeLaws {
+  def apply[A](implicit ev: JoinSemilattice[A]): JoinSemilatticeLaws[A] =
+    new JoinSemilatticeLaws[A] { def S: JoinSemilattice[A] = ev }
+}
diff --git a/laws/src/main/scala/algebra/laws/LatticeLaws.scala b/laws/src/main/scala/algebra/laws/LatticeLaws.scala
index 17d2e97e..22c330ba 100644
--- a/laws/src/main/scala/algebra/laws/LatticeLaws.scala
+++ b/laws/src/main/scala/algebra/laws/LatticeLaws.scala
@@ -5,111 +5,15 @@ import algebra.lattice._
 
 import cats.kernel.laws._
 
-import org.scalacheck.{Arbitrary, Prop}
-import org.scalacheck.Prop._
 
-object LatticeLaws {
-  def apply[A: Eq: Arbitrary] = new LatticeLaws[A] {
-    def Equ = Eq[A]
-    def Arb = implicitly[Arbitrary[A]]
-  }
-}
-
-trait LatticeLaws[A] extends GroupLaws[A] {
-
-  implicit def Equ: Eq[A]
-  implicit def Arb: Arbitrary[A]
-
-  def joinSemilattice(implicit A: JoinSemilattice[A]) = new LatticeProperties(
-    name = "joinSemilattice",
-    parents = Nil,
-    join = Some(semilattice(A.joinSemilattice)),
-    meet = None,
-    Rules.serializable(A)
-  )
-
-  def meetSemilattice(implicit A: MeetSemilattice[A]) = new LatticeProperties(
-    name = "meetSemilattice",
-    parents = Nil,
-    join = None,
-    meet = Some(semilattice(A.meetSemilattice)),
-    Rules.serializable(A)
-  )
-
-  def lattice(implicit A: Lattice[A]) = new LatticeProperties(
-    name = "lattice",
-    parents = Seq(joinSemilattice, meetSemilattice),
-    join = Some(semilattice(A.joinSemilattice)),
-    meet = Some(semilattice(A.meetSemilattice)),
-    "absorption" -> forAll { (x: A, y: A) =>
-      (A.join(x, A.meet(x, y)) ?== x) && (A.meet(x, A.join(x, y)) ?== x)
-    }
-  )
-
-  def distributiveLattice(implicit A: DistributiveLattice[A]) = new LatticeProperties(
-    name = "distributiveLattice",
-    parents = Seq(lattice),
-    join = Some(semilattice(A.joinSemilattice)),
-    meet = Some(semilattice(A.meetSemilattice)),
-    "distributive" -> forAll { (x: A, y: A, z: A) =>
-      (A.join(x, A.meet(y, z)) ?== A.meet(A.join(x, y), A.join(x, z))) &&
-        (A.meet(x, A.join(y, z)) ?== A.join(A.meet(x, y), A.meet(x, z)))
-    }
-  )
-
-  def boundedJoinSemilattice(implicit A: BoundedJoinSemilattice[A]) = new LatticeProperties(
-    name = "boundedJoinSemilattice",
-    parents = Seq(joinSemilattice),
-    join = Some(boundedSemilattice(A.joinSemilattice)),
-    meet = None
-  )
+trait LatticeLaws[A] extends JoinSemilatticeLaws[A] with MeetSemilatticeLaws[A] {
+  override implicit def S: Lattice[A]
 
-  def boundedMeetSemilattice(implicit A: BoundedMeetSemilattice[A]) = new LatticeProperties(
-    name = "boundedMeetSemilattice",
-    parents = Seq(meetSemilattice),
-    join = None,
-    meet = Some(boundedSemilattice(A.meetSemilattice))
-  )
-
-  def boundedJoinLattice(implicit A: Lattice[A] with BoundedJoinSemilattice[A]) = new LatticeProperties(
-    name = "boundedJoinLattice",
-    parents = Seq(boundedJoinSemilattice, lattice),
-    join = Some(boundedSemilattice(A.joinSemilattice)),
-    meet = Some(semilattice(A.meetSemilattice))
-  )
-
-  def boundedMeetLattice(implicit A: Lattice[A] with BoundedMeetSemilattice[A]) = new LatticeProperties(
-    name = "boundedMeetLattice",
-    parents = Seq(boundedMeetSemilattice, lattice),
-    join = Some(semilattice(A.joinSemilattice)),
-    meet = Some(boundedSemilattice(A.meetSemilattice))
-  )
-
-  def boundedLattice(implicit A: BoundedLattice[A]) = new LatticeProperties(
-    name = "boundedLattice",
-    parents = Seq(boundedJoinSemilattice, boundedMeetSemilattice, lattice),
-    join = Some(boundedSemilattice(A.joinSemilattice)),
-    meet = Some(boundedSemilattice(A.meetSemilattice))
-  )
-
-  def boundedDistributiveLattice(implicit A: BoundedDistributiveLattice[A]) = new LatticeProperties(
-    name = "boundedLattice",
-    parents = Seq(boundedLattice, distributiveLattice),
-    join = Some(boundedSemilattice(A.joinSemilattice)),
-    meet = Some(boundedSemilattice(A.meetSemilattice))
-  )
-
-  class LatticeProperties(
-    val name: String,
-    val parents: Seq[LatticeProperties],
-    val join: Option[GroupProperties],
-    val meet: Option[GroupProperties],
-    val props: (String, Prop)*
-  ) extends RuleSet {
-    private val _m = meet map { "meet" -> _ }
-    private val _j = join map { "join" -> _ }
-
-    val bases = _m.toList ::: _j.toList
-  }
+  def absorption(x: A, y: A)(implicit E: Eq[A]): IsEq[Boolean] =
+    (E.eqv(S.join(x, S.meet(x, y)), x) && E.eqv(S.meet(x, S.join(x, y)), x)) <-> true
+}
 
+object LatticeLaws {
+  def apply[A](implicit ev: Lattice[A]): LatticeLaws[A] =
+    new LatticeLaws[A] { def S: Lattice[A] = ev }
 }
diff --git a/laws/src/main/scala/algebra/laws/MeetSemilatticeLaws.scala b/laws/src/main/scala/algebra/laws/MeetSemilatticeLaws.scala
new file mode 100644
index 00000000..3145fef1
--- /dev/null
+++ b/laws/src/main/scala/algebra/laws/MeetSemilatticeLaws.scala
@@ -0,0 +1,14 @@
+package algebra
+package laws
+
+import cats.kernel.laws._
+import algebra.lattice._
+
+trait MeetSemilatticeLaws[A] extends SemilatticeLaws[A] {
+  override implicit def S: MeetSemilattice[A]
+}
+
+object MeetSemilatticeLaws {
+  def apply[A](implicit ev: MeetSemilattice[A]): MeetSemilatticeLaws[A] =
+    new MeetSemilatticeLaws[A] { def S: MeetSemilattice[A] = ev }
+}
diff --git a/laws/src/main/scala/algebra/laws/MultiplicativeCommutativeGroupLaws.scala b/laws/src/main/scala/algebra/laws/MultiplicativeCommutativeGroupLaws.scala
new file mode 100755
index 00000000..699948e9
--- /dev/null
+++ b/laws/src/main/scala/algebra/laws/MultiplicativeCommutativeGroupLaws.scala
@@ -0,0 +1,13 @@
+package algebra
+package laws
+
+import algebra.ring._
+
+trait MultiplicativeCommutativeGroupLaws[A] extends MultiplicativeGroupLaws[A] with MultiplicativeCommutativeMonoidLaws[A] {
+  override implicit def S: MultiplicativeCommutativeGroup[A]
+}
+
+object MultiplicativeCommutativeGroupLaws {
+  def apply[A](implicit ev: MultiplicativeCommutativeGroup[A]): MultiplicativeCommutativeGroupLaws[A] =
+    new MultiplicativeCommutativeGroupLaws[A] { def S: MultiplicativeCommutativeGroup[A] = ev }
+}
diff --git a/laws/src/main/scala/algebra/laws/MultiplicativeCommutativeMonoidLaws.scala b/laws/src/main/scala/algebra/laws/MultiplicativeCommutativeMonoidLaws.scala
new file mode 100755
index 00000000..854ee6e9
--- /dev/null
+++ b/laws/src/main/scala/algebra/laws/MultiplicativeCommutativeMonoidLaws.scala
@@ -0,0 +1,13 @@
+package algebra
+package laws
+
+import algebra.ring._
+
+trait MultiplicativeCommutativeMonoidLaws[A] extends MultiplicativeMonoidLaws[A] with MultiplicativeCommutativeSemigroupLaws[A] {
+  override implicit def S: MultiplicativeCommutativeMonoid[A]
+}
+
+object MultiplicativeCommutativeMonoidLaws {
+  def apply[A](implicit ev: MultiplicativeCommutativeMonoid[A]): MultiplicativeCommutativeMonoidLaws[A] =
+  new MultiplicativeCommutativeMonoidLaws[A] { def S: MultiplicativeCommutativeMonoid[A] = ev }
+}
diff --git a/laws/src/main/scala/algebra/laws/MultiplicativeCommutativeSemigroupLaws.scala b/laws/src/main/scala/algebra/laws/MultiplicativeCommutativeSemigroupLaws.scala
new file mode 100755
index 00000000..1c03fe24
--- /dev/null
+++ b/laws/src/main/scala/algebra/laws/MultiplicativeCommutativeSemigroupLaws.scala
@@ -0,0 +1,18 @@
+package algebra
+package laws
+
+import algebra.ring._
+import cats.kernel.laws._
+
+trait MultiplicativeCommutativeSemigroupLaws[A] extends MultiplicativeSemigroupLaws[A] {
+  override implicit def S: MultiplicativeCommutativeSemigroup[A]
+
+  def timesCommutative(x: A, y: A): IsEq[A] =
+    S.times(x, y) <-> S.times(y, x)
+
+}
+
+object MultiplicativeCommutativeSemigroupLaws {
+  def apply[A](implicit ev: MultiplicativeCommutativeSemigroup[A]): MultiplicativeCommutativeSemigroupLaws[A] =
+    new MultiplicativeCommutativeSemigroupLaws[A] { def S: MultiplicativeCommutativeSemigroup[A] = ev }
+}
diff --git a/laws/src/main/scala/algebra/laws/MultiplicativeGroupLaws.scala b/laws/src/main/scala/algebra/laws/MultiplicativeGroupLaws.scala
new file mode 100755
index 00000000..775046ec
--- /dev/null
+++ b/laws/src/main/scala/algebra/laws/MultiplicativeGroupLaws.scala
@@ -0,0 +1,24 @@
+package algebra
+package laws
+
+import algebra.ring._
+import cats.kernel.laws._
+
+trait MultiplicativeGroupLaws[A] extends MultiplicativeMonoidLaws[A] {
+  override implicit def S: MultiplicativeGroup[A]
+
+  def leftReciprocal(x: A): IsEq[A] =
+    S.times(S.reciprocal(x), x) <-> S.one
+
+  def rightReciprocal(x: A): IsEq[A] =
+    S.times(x, S.reciprocal(x)) <-> S.one
+
+  def consistentDiv(x: A, y: A): IsEq[A] =
+    S.div(x, y) <-> S.times(x, S.reciprocal(y))
+
+}
+
+object MultiplicativeGroupLaws {
+  def apply[A](implicit ev: MultiplicativeGroup[A]): MultiplicativeGroupLaws[A] =
+    new MultiplicativeGroupLaws[A] { def S: MultiplicativeGroup[A] = ev }
+}
diff --git a/laws/src/main/scala/algebra/laws/MultiplicativeMonoidLaws.scala b/laws/src/main/scala/algebra/laws/MultiplicativeMonoidLaws.scala
new file mode 100755
index 00000000..76c1ec42
--- /dev/null
+++ b/laws/src/main/scala/algebra/laws/MultiplicativeMonoidLaws.scala
@@ -0,0 +1,29 @@
+package algebra
+package laws
+
+import algebra.ring._
+import cats.kernel.laws._
+
+trait MultiplicativeMonoidLaws[A] extends MultiplicativeSemigroupLaws[A] {
+  override implicit def S: MultiplicativeMonoid[A]
+
+  def leftOne(a: A): IsEq[A] =
+    S.times(S.one, a) <-> a
+
+  def rightOne(a: A): IsEq[A] =
+    S.times(a, S.one) <-> a
+
+  def pow0(a: A): IsEq[A] =
+    S.pow(a, 0) <-> S.one
+
+  def product: IsEq[A] =
+    S.product(Nil) <-> S.one
+
+  def isOne(a: A, eqv: Eq[A]): IsEq[Boolean] =
+    eqv.eqv(a, S.one) <-> S.isOne(a)(eqv)
+}
+
+object MultiplicativeMonoidLaws {
+  def apply[A](implicit ev: MultiplicativeMonoid[A]): MultiplicativeMonoidLaws[A] =
+    new MultiplicativeMonoidLaws[A] { def S: MultiplicativeMonoid[A] = ev }
+}
diff --git a/laws/src/main/scala/algebra/laws/MultiplicativeSemigroupLaws.scala b/laws/src/main/scala/algebra/laws/MultiplicativeSemigroupLaws.scala
new file mode 100755
index 00000000..9d9693bc
--- /dev/null
+++ b/laws/src/main/scala/algebra/laws/MultiplicativeSemigroupLaws.scala
@@ -0,0 +1,29 @@
+package algebra
+package laws
+
+import algebra.ring._
+import cats.kernel.laws._
+
+trait MultiplicativeSemigroupLaws[A] {
+  implicit def S: MultiplicativeSemigroup[A]
+
+  def timesAssociative(x: A, y: A, z: A): IsEq[A] =
+    S.times(S.times(x, y), z) <-> S.times(x, S.times(y, z))
+
+  def pow1(a: A): IsEq[A] =
+    S.pow(a, 1) <-> a
+
+  def pow2(a: A): IsEq[A] =
+    S.pow(a, 2) <-> S.times(a, a)
+
+  def pow3(a: A): IsEq[A] =
+    S.pow(a, 3) <-> S.times(S.times(a, a), a)
+
+  def tryProduct(xs: Vector[A]): IsEq[Option[A]] =
+    S.tryProduct(xs) <-> xs.reduceOption(S.times)
+}
+
+object MultiplicativeSemigroupLaws {
+  def apply[A](implicit ev: MultiplicativeSemigroup[A]): MultiplicativeSemigroupLaws[A] =
+    new MultiplicativeSemigroupLaws[A] { def S: MultiplicativeSemigroup[A] = ev }
+}
diff --git a/laws/src/main/scala/algebra/laws/RigLaws.scala b/laws/src/main/scala/algebra/laws/RigLaws.scala
new file mode 100755
index 00000000..3dd19d6f
--- /dev/null
+++ b/laws/src/main/scala/algebra/laws/RigLaws.scala
@@ -0,0 +1,13 @@
+package algebra
+package laws
+
+import algebra.ring._
+
+trait RigLaws[A] extends SemiringLaws[A] with MultiplicativeMonoidLaws[A] {
+  override implicit def S: Rig[A]
+}
+
+object RigLaws {
+  def apply[A](implicit ev: Rig[A]): RigLaws[A] =
+    new RigLaws[A] { def S: Rig[A] = ev }
+}
diff --git a/laws/src/main/scala/algebra/laws/RingLaws.scala b/laws/src/main/scala/algebra/laws/RingLaws.scala
index 307d13e8..407c4782 100644
--- a/laws/src/main/scala/algebra/laws/RingLaws.scala
+++ b/laws/src/main/scala/algebra/laws/RingLaws.scala
@@ -3,6 +3,16 @@ package laws
 
 import algebra.ring._
 
+trait RingLaws[A] extends RigLaws[A] with RngLaws[A] {
+  override implicit def S: Ring[A]
+}
+
+object RingLaws {
+  def apply[A](implicit ev: Ring[A]): RingLaws[A] =
+    new RingLaws[A] { def S: Ring[A] = ev }
+}
+/*
+
 import catalysts.Platform
 import cats.kernel.laws._
 
@@ -286,3 +296,4 @@ trait RingLaws[A] extends GroupLaws[A] { self =>
     def bases = Seq("additive" -> al, "multiplicative" -> ml)
   }
 }
+*/
diff --git a/laws/src/main/scala/algebra/laws/RngLaws.scala b/laws/src/main/scala/algebra/laws/RngLaws.scala
new file mode 100755
index 00000000..a14e9de2
--- /dev/null
+++ b/laws/src/main/scala/algebra/laws/RngLaws.scala
@@ -0,0 +1,13 @@
+package algebra
+package laws
+
+import algebra.ring._
+
+trait RngLaws[A] extends SemiringLaws[A] with AdditiveCommutativeGroupLaws[A] {
+  override implicit def S: Rng[A]
+}
+
+object RngLaws {
+  def apply[A](implicit ev: Rng[A]): RngLaws[A] =
+    new RngLaws[A] { def S: Rng[A] = ev }
+}
diff --git a/laws/src/main/scala/algebra/laws/SemiringLaws.scala b/laws/src/main/scala/algebra/laws/SemiringLaws.scala
new file mode 100755
index 00000000..ab95ca2a
--- /dev/null
+++ b/laws/src/main/scala/algebra/laws/SemiringLaws.scala
@@ -0,0 +1,26 @@
+package algebra
+package laws
+
+import algebra.ring._
+import cats.kernel.laws._
+
+trait SemiringLaws[A] extends AdditiveCommutativeMonoidLaws[A] with MultiplicativeSemigroupLaws[A] {
+  override implicit def S: Semiring[A]
+
+  def leftDistributive(x: A, y: A, z: A): IsEq[A] =
+    S.times(x, S.plus(y, z)) <-> S.plus(S.times(x, y), S.times(x, z))
+
+  def rightDistributive(x: A, y: A, z: A): IsEq[A] =
+    S.times(S.plus(x, y), z) <-> S.plus(S.times(x, z), S.times(y, z))
+
+  def zeroLeftAnnihilates(a: A): IsEq[A] =
+    S.times(S.zero, a) <-> S.zero
+
+  def zeroRightAnnihilates(a: A): IsEq[A] =
+    S.times(a, S.zero) <-> S.zero
+}
+
+object SemiringLaws {
+  def apply[A](implicit ev: Semiring[A]): SemiringLaws[A] =
+    new SemiringLaws[A] { def S: Semiring[A] = ev }
+}
diff --git a/laws/src/main/scala/algebra/laws/discipline/AdditiveCommutativeGroupTests.scala b/laws/src/main/scala/algebra/laws/discipline/AdditiveCommutativeGroupTests.scala
new file mode 100755
index 00000000..33bc2e1d
--- /dev/null
+++ b/laws/src/main/scala/algebra/laws/discipline/AdditiveCommutativeGroupTests.scala
@@ -0,0 +1,22 @@
+package algebra
+package laws
+package discipline
+
+import algebra.ring._
+import org.scalacheck.Arbitrary
+
+trait AdditiveCommutativeGroupTests[A] extends AdditiveCommutativeMonoidTests[A] with AdditiveGroupTests[A] {
+  def laws: AdditiveCommutativeGroupLaws[A]
+
+  def additiveCommutativeGroup(implicit arbA: Arbitrary[A], eqA: Eq[A]): CommutativeRuleSet =
+    new CommutativeRuleSet(
+      "additiveCommutativeGroup",
+      additiveGroup,
+      Some(additiveCommutativeMonoid)
+    )
+}
+
+object AdditiveCommutativeGroupTests {
+  def apply[A: AdditiveCommutativeGroup]: AdditiveCommutativeGroupTests[A] =
+    new AdditiveCommutativeGroupTests[A] { def laws: AdditiveCommutativeGroupLaws[A] = AdditiveCommutativeGroupLaws[A] }
+}
diff --git a/laws/src/main/scala/algebra/laws/discipline/AdditiveCommutativeMonoidTests.scala b/laws/src/main/scala/algebra/laws/discipline/AdditiveCommutativeMonoidTests.scala
new file mode 100755
index 00000000..0fba6ec7
--- /dev/null
+++ b/laws/src/main/scala/algebra/laws/discipline/AdditiveCommutativeMonoidTests.scala
@@ -0,0 +1,22 @@
+package algebra
+package laws
+package discipline
+
+import algebra.ring._
+import org.scalacheck.Arbitrary
+
+trait AdditiveCommutativeMonoidTests[A] extends AdditiveCommutativeSemigroupTests[A] with AdditiveMonoidTests[A] {
+  def laws: AdditiveCommutativeMonoidLaws[A]
+
+  def additiveCommutativeMonoid(implicit arbA: Arbitrary[A], eqA: Eq[A]): CommutativeRuleSet =
+    new CommutativeRuleSet(
+      "additiveCommutativeMonoid",
+      additiveMonoid,
+      Some(additiveCommutativeSemigroup)
+    )
+}
+
+object AdditiveCommutativeMonoidTests {
+  def apply[A: AdditiveCommutativeMonoid]: AdditiveCommutativeMonoidTests[A] =
+    new AdditiveCommutativeMonoidTests[A] { def laws: AdditiveCommutativeMonoidLaws[A] = AdditiveCommutativeMonoidLaws[A] }
+}
diff --git a/laws/src/main/scala/algebra/laws/discipline/AdditiveCommutativeSemigroupTests.scala b/laws/src/main/scala/algebra/laws/discipline/AdditiveCommutativeSemigroupTests.scala
new file mode 100755
index 00000000..b58cfdae
--- /dev/null
+++ b/laws/src/main/scala/algebra/laws/discipline/AdditiveCommutativeSemigroupTests.scala
@@ -0,0 +1,25 @@
+package algebra
+package laws
+package discipline
+
+import algebra.ring._
+import org.scalacheck.{Arbitrary, Prop}
+import Prop._
+
+trait AdditiveCommutativeSemigroupTests[A] extends AdditiveSemigroupTests[A] with CommutativeTests {
+
+  def laws: AdditiveCommutativeSemigroupLaws[A]
+
+  def additiveCommutativeSemigroup(implicit arbA: Arbitrary[A], eqA: Eq[A]): CommutativeRuleSet =
+    new CommutativeRuleSet(
+      "additiveCommutativeSemigroup",
+      additiveSemigroup,
+      None,
+      "plus commutative" -> forAll(laws.plusCommutative _)
+    )
+}
+
+object AdditiveCommutativeSemigroupTests {
+  def apply[A: AdditiveCommutativeSemigroup]: AdditiveCommutativeSemigroupTests[A] =
+    new AdditiveCommutativeSemigroupTests[A] { def laws: AdditiveCommutativeSemigroupLaws[A] = AdditiveCommutativeSemigroupLaws[A] }
+}
diff --git a/laws/src/main/scala/algebra/laws/discipline/AdditiveGroupTests.scala b/laws/src/main/scala/algebra/laws/discipline/AdditiveGroupTests.scala
new file mode 100755
index 00000000..e0eb0e8c
--- /dev/null
+++ b/laws/src/main/scala/algebra/laws/discipline/AdditiveGroupTests.scala
@@ -0,0 +1,26 @@
+package algebra
+package laws
+package discipline
+
+import algebra.ring._
+import org.scalacheck.Arbitrary
+import org.scalacheck.Prop.forAll
+
+trait AdditiveGroupTests[A] extends AdditiveMonoidTests[A] {
+
+  def laws: AdditiveGroupLaws[A]
+
+  def additiveGroup(implicit arbA: Arbitrary[A], eqA: Eq[A]): RuleSet =
+    new DefaultRuleSet(
+      "additiveGroup",
+      Some(additiveMonoid),
+      "left negate" -> forAll(laws.leftNegate _),
+      "right negate" -> forAll(laws.rightNegate _),
+      "consistent minus" -> forAll(laws.consistentMinus _)
+    )
+}
+
+object AdditiveGroupTests {
+  def apply[A: AdditiveGroup]: AdditiveGroupTests[A] =
+    new AdditiveGroupTests[A] { def laws: AdditiveGroupLaws[A] = AdditiveGroupLaws[A] }
+}
diff --git a/laws/src/main/scala/algebra/laws/discipline/AdditiveMonoidTests.scala b/laws/src/main/scala/algebra/laws/discipline/AdditiveMonoidTests.scala
new file mode 100755
index 00000000..736f3ea6
--- /dev/null
+++ b/laws/src/main/scala/algebra/laws/discipline/AdditiveMonoidTests.scala
@@ -0,0 +1,29 @@
+package algebra
+package laws
+package discipline
+
+import algebra.ring._
+import org.scalacheck.{Arbitrary, Prop}
+import Prop._
+import cats.kernel.instances.boolean._
+
+trait AdditiveMonoidTests[A] extends AdditiveSemigroupTests[A] {
+
+  def laws: AdditiveMonoidLaws[A]
+
+  def additiveMonoid(implicit arbA: Arbitrary[A], eqA: Eq[A]): RuleSet =
+    new DefaultRuleSet(
+      "additiveMonoid",
+      Some(additiveSemigroup),
+      "left zero" -> forAll(laws.leftZero _),
+      "right zero" -> forAll(laws.rightZero _),
+      "sumN0" -> forAll(laws.sumN0 _),
+      "sumAll" -> laws.sumAll,
+      "isZero" -> forAll((a: A) => laws.isZero(a, eqA))
+    )
+}
+
+object AdditiveMonoidTests {
+  def apply[A: AdditiveMonoid]: AdditiveMonoidTests[A] =
+    new AdditiveMonoidTests[A] { def laws: AdditiveMonoidLaws[A] = AdditiveMonoidLaws[A] }
+}
diff --git a/laws/src/main/scala/algebra/laws/discipline/AdditiveSemigroupTests.scala b/laws/src/main/scala/algebra/laws/discipline/AdditiveSemigroupTests.scala
new file mode 100755
index 00000000..9915c1cf
--- /dev/null
+++ b/laws/src/main/scala/algebra/laws/discipline/AdditiveSemigroupTests.scala
@@ -0,0 +1,30 @@
+package algebra
+package laws
+package discipline
+
+import algebra.ring._
+import org.scalacheck.{Arbitrary, Prop}
+import Prop._
+import org.typelevel.discipline.Laws
+import cats.kernel.instances.option._
+
+trait AdditiveSemigroupTests[A] extends Laws {
+  def laws: AdditiveSemigroupLaws[A]
+
+  def additiveSemigroup(implicit arbA: Arbitrary[A], eqA: Eq[A]): RuleSet =
+    new DefaultRuleSet(
+      "additiveSemigroup",
+      None,
+      "plus associative" -> forAll(laws.plusAssociative _),
+      "sumN1" -> forAll(laws.sumN1 _),
+      "sumN2" -> forAll(laws.sumN2 _),
+      "sumN3" -> forAll(laws.sumN3 _),
+      "trySum" -> forAll(laws.trySum _)
+    )
+
+}
+
+object AdditiveSemigroupTests {
+  def apply[A: AdditiveSemigroup]: AdditiveSemigroupTests[A] =
+    new AdditiveSemigroupTests[A] { def laws: AdditiveSemigroupLaws[A] = AdditiveSemigroupLaws[A] }
+}
diff --git a/laws/src/main/scala/algebra/laws/discipline/BoundedDistributiveLatticeTests.scala b/laws/src/main/scala/algebra/laws/discipline/BoundedDistributiveLatticeTests.scala
new file mode 100644
index 00000000..45211a5e
--- /dev/null
+++ b/laws/src/main/scala/algebra/laws/discipline/BoundedDistributiveLatticeTests.scala
@@ -0,0 +1,25 @@
+package algebra
+package laws
+package discipline
+
+import algebra.lattice.BoundedDistributiveLattice
+import org.scalacheck.{Arbitrary, Prop}
+
+trait BoundedDistributiveLatticeTests[A] extends DistributiveLatticeTests[A] with BoundedLatticeTests[A] {
+  def laws: BoundedDistributiveLatticeLaws[A]
+
+  def boundedDistributiveLattice(implicit arbA: Arbitrary[A], eqA: Eq[A]): RuleSet =
+    new RuleSet {
+      def name: String = "boundedDistributiveLattice"
+      def bases: Seq[(String, RuleSet)] = Nil
+      def parents: Seq[RuleSet] = Seq(distributiveLattice, boundedLattice)
+      def props: Seq[(String, Prop)] = Nil
+    }
+}
+
+object BoundedDistributiveLatticeTests {
+  def apply[A : BoundedDistributiveLattice]: BoundedDistributiveLatticeTests[A] =
+    new BoundedDistributiveLatticeTests[A] {
+      def laws: BoundedDistributiveLatticeLaws[A] = BoundedDistributiveLatticeLaws[A]
+    }
+}
diff --git a/laws/src/main/scala/algebra/laws/discipline/BoundedJoinSemilatticeTests.scala b/laws/src/main/scala/algebra/laws/discipline/BoundedJoinSemilatticeTests.scala
new file mode 100644
index 00000000..f7d58516
--- /dev/null
+++ b/laws/src/main/scala/algebra/laws/discipline/BoundedJoinSemilatticeTests.scala
@@ -0,0 +1,24 @@
+package algebra
+package laws
+package discipline
+
+import algebra.lattice.BoundedJoinSemilattice
+import cats.kernel.laws.discipline.BoundedSemilatticeTests
+import org.scalacheck.{Arbitrary, Prop}
+
+trait BoundedJoinSemilatticeTests[A] extends BoundedSemilatticeTests[A] with JoinSemilatticeTests[A] {
+  def laws: BoundedJoinSemilatticeLaws[A]
+
+  def boundedJoinSemilattice(implicit arbA: Arbitrary[A], eqA: Eq[A]): RuleSet =
+    new RuleSet {
+      def name: String = "boundedJoinSemilattice"
+      def bases: Seq[(String, RuleSet)] = Nil
+      def parents: Seq[RuleSet] = Seq(boundedSemilattice, joinSemilattice)
+      def props: Seq[(String, Prop)] = Nil
+    }
+}
+
+object BoundedJoinSemilatticeTests {
+  def apply[A : BoundedJoinSemilattice]: BoundedJoinSemilatticeTests[A] =
+    new BoundedJoinSemilatticeTests[A] { def laws: BoundedJoinSemilatticeLaws[A] = BoundedJoinSemilatticeLaws[A] }
+}
diff --git a/laws/src/main/scala/algebra/laws/discipline/BoundedLatticeTests.scala b/laws/src/main/scala/algebra/laws/discipline/BoundedLatticeTests.scala
new file mode 100644
index 00000000..81799ba7
--- /dev/null
+++ b/laws/src/main/scala/algebra/laws/discipline/BoundedLatticeTests.scala
@@ -0,0 +1,27 @@
+package algebra
+package laws
+package discipline
+
+import algebra.lattice.BoundedLattice
+import org.scalacheck.{Arbitrary, Prop}
+import Prop.forAll
+import cats.kernel.instances.boolean._
+
+trait BoundedLatticeTests[A] extends LatticeTests[A] with BoundedJoinSemilatticeTests[A] with BoundedMeetSemilatticeTests[A] {
+  def laws: BoundedLatticeLaws[A]
+
+  def boundedLattice(implicit arbA: Arbitrary[A], eqA: Eq[A]): RuleSet =
+    new RuleSet {
+      def name: String = "boundedLattice"
+      def bases: Seq[(String, RuleSet)] = Nil
+      def parents: Seq[RuleSet] = Seq(lattice, boundedJoinSemilattice, boundedMeetSemilattice)
+      def props: Seq[(String, Prop)] = Seq(
+        "lattice absorption" -> forAll(laws.absorption _)
+      )
+    }
+}
+
+object BoundedLatticeTests {
+  def apply[A : BoundedLattice]: BoundedLatticeTests[A] =
+    new BoundedLatticeTests[A] { def laws: BoundedLatticeLaws[A] = BoundedLatticeLaws[A] }
+}
diff --git a/laws/src/main/scala/algebra/laws/discipline/BoundedMeetSemilatticeTests.scala b/laws/src/main/scala/algebra/laws/discipline/BoundedMeetSemilatticeTests.scala
new file mode 100644
index 00000000..39982176
--- /dev/null
+++ b/laws/src/main/scala/algebra/laws/discipline/BoundedMeetSemilatticeTests.scala
@@ -0,0 +1,24 @@
+package algebra
+package laws
+package discipline
+
+import algebra.lattice.BoundedMeetSemilattice
+import cats.kernel.laws.discipline.BoundedSemilatticeTests
+import org.scalacheck.{Arbitrary, Prop}
+
+trait BoundedMeetSemilatticeTests[A] extends BoundedSemilatticeTests[A] with MeetSemilatticeTests[A] {
+  def laws: BoundedMeetSemilatticeLaws[A]
+
+  def boundedMeetSemilattice(implicit arbA: Arbitrary[A], eqA: Eq[A]): RuleSet =
+    new RuleSet {
+      def name: String = "boundedMeetSemilattice"
+      def bases: Seq[(String, RuleSet)] = Nil
+      def parents: Seq[RuleSet] = Seq(boundedSemilattice, meetSemilattice)
+      def props: Seq[(String, Prop)] = Nil
+    }
+}
+
+object BoundedMeetSemilatticeTests {
+  def apply[A : BoundedMeetSemilattice]: BoundedMeetSemilatticeTests[A] =
+    new BoundedMeetSemilatticeTests[A] { def laws: BoundedMeetSemilatticeLaws[A] = BoundedMeetSemilatticeLaws[A] }
+}
diff --git a/laws/src/main/scala/algebra/laws/discipline/CommutativeRigTests.scala b/laws/src/main/scala/algebra/laws/discipline/CommutativeRigTests.scala
new file mode 100755
index 00000000..f0d91bdd
--- /dev/null
+++ b/laws/src/main/scala/algebra/laws/discipline/CommutativeRigTests.scala
@@ -0,0 +1,22 @@
+package algebra
+package laws
+package discipline
+
+import algebra.ring._
+import org.scalacheck.Arbitrary
+
+trait CommutativeRigTests[A] extends RigTests[A] with CommutativeSemiringTests[A] {
+  def laws: CommutativeRigLaws[A]
+
+  def commutativeRig(implicit arbA: Arbitrary[A], eqA: Eq[A]): CommutativeRingRuleSet =
+    new CommutativeRingRuleSet(
+      "commutativeRig",
+      rig,
+      Seq(commutativeSemiring)
+    )
+}
+
+object CommutativeRigTests {
+  def apply[A: CommutativeRig]: CommutativeRigTests[A] =
+    new CommutativeRigTests[A] { def laws: CommutativeRigLaws[A] = CommutativeRigLaws[A] }
+}
diff --git a/laws/src/main/scala/algebra/laws/discipline/CommutativeRingTests.scala b/laws/src/main/scala/algebra/laws/discipline/CommutativeRingTests.scala
new file mode 100755
index 00000000..d63be44b
--- /dev/null
+++ b/laws/src/main/scala/algebra/laws/discipline/CommutativeRingTests.scala
@@ -0,0 +1,22 @@
+package algebra
+package laws
+package discipline
+
+import algebra.ring._
+import org.scalacheck.Arbitrary
+
+trait CommutativeRingTests[A] extends RingTests[A] with CommutativeRigTests[A] with CommutativeRngTests[A] {
+  def laws: CommutativeRingLaws[A]
+
+  def commutativeRing(implicit arbA: Arbitrary[A], eqA: Eq[A]): CommutativeRingRuleSet =
+    new CommutativeRingRuleSet(
+      "commutativeRing",
+      rng,
+      Seq(commutativeRig, commutativeRng)
+    )
+}
+
+object CommutativeRingTests {
+  def apply[A: CommutativeRing]: CommutativeRingTests[A] =
+    new CommutativeRingTests[A] { def laws: CommutativeRingLaws[A] = CommutativeRingLaws[A] }
+}
diff --git a/laws/src/main/scala/algebra/laws/discipline/CommutativeRngTests.scala b/laws/src/main/scala/algebra/laws/discipline/CommutativeRngTests.scala
new file mode 100755
index 00000000..924376ed
--- /dev/null
+++ b/laws/src/main/scala/algebra/laws/discipline/CommutativeRngTests.scala
@@ -0,0 +1,22 @@
+package algebra
+package laws
+package discipline
+
+import algebra.ring._
+import org.scalacheck.Arbitrary
+
+trait CommutativeRngTests[A] extends RngTests[A] with CommutativeSemiringTests[A] {
+  def laws: CommutativeRngLaws[A]
+
+  def commutativeRng(implicit arbA: Arbitrary[A], eqA: Eq[A]): CommutativeRingRuleSet =
+    new CommutativeRingRuleSet(
+      "commutativeRng",
+      rng,
+      Seq(commutativeSemiring)
+    )
+}
+
+object CommutativeRngTests {
+  def apply[A: CommutativeRng]: CommutativeRngTests[A] =
+    new CommutativeRngTests[A] { def laws: CommutativeRngLaws[A] = CommutativeRngLaws[A] }
+}
diff --git a/laws/src/main/scala/algebra/laws/discipline/CommutativeSemiringTests.scala b/laws/src/main/scala/algebra/laws/discipline/CommutativeSemiringTests.scala
new file mode 100755
index 00000000..69cc8192
--- /dev/null
+++ b/laws/src/main/scala/algebra/laws/discipline/CommutativeSemiringTests.scala
@@ -0,0 +1,31 @@
+package algebra
+package laws
+package discipline
+
+import algebra.ring._
+import org.scalacheck.{Arbitrary, Prop}
+
+trait CommutativeSemiringTests[A] extends SemiringTests[A] with MultiplicativeCommutativeSemigroupTests[A] {
+  def laws: CommutativeSemiringLaws[A]
+
+  def commutativeSemiring(implicit arbA: Arbitrary[A], eqA: Eq[A]): CommutativeRingRuleSet =
+    new CommutativeRingRuleSet(
+      "commutativeSemiring",
+      semiring,
+      Nil
+    )
+
+  class CommutativeRingRuleSet(val name: String,
+    val noncommutativeParent: RingRuleSet,
+    val commutativeParents: Seq[CommutativeRingRuleSet],
+    val props: (String, Prop)*
+  ) extends RuleSet {
+    def bases = Nil
+    val parents = Seq(noncommutativeParent) ++ commutativeParents
+  }
+}
+
+object CommutativeSemiringTests {
+  def apply[A: CommutativeSemiring]: CommutativeSemiringTests[A] =
+    new CommutativeSemiringTests[A] { def laws: CommutativeSemiringLaws[A] = CommutativeSemiringLaws[A] }
+}
diff --git a/laws/src/main/scala/algebra/laws/discipline/CommutativeTests.scala b/laws/src/main/scala/algebra/laws/discipline/CommutativeTests.scala
new file mode 100644
index 00000000..238c1ff5
--- /dev/null
+++ b/laws/src/main/scala/algebra/laws/discipline/CommutativeTests.scala
@@ -0,0 +1,16 @@
+package algebra.laws.discipline
+
+import org.typelevel.discipline.Laws
+import org.scalacheck.Prop
+
+trait CommutativeTests { self: Laws =>
+
+  class CommutativeRuleSet(val name: String,
+                           val noncommutativeParent: RuleSet,
+                           val commutativeParent: Option[CommutativeRuleSet],
+                           val props: (String, Prop)*
+                          ) extends RuleSet {
+    val parents = Seq(noncommutativeParent) ++ commutativeParent.toSeq
+    val bases = Nil
+  }
+}
diff --git a/laws/src/main/scala/algebra/laws/discipline/DistributiveLatticeTests.scala b/laws/src/main/scala/algebra/laws/discipline/DistributiveLatticeTests.scala
new file mode 100644
index 00000000..bc4f7698
--- /dev/null
+++ b/laws/src/main/scala/algebra/laws/discipline/DistributiveLatticeTests.scala
@@ -0,0 +1,24 @@
+package algebra
+package laws
+package discipline
+
+import algebra.lattice.DistributiveLattice
+import org.scalacheck.Arbitrary
+import org.scalacheck.Prop.forAll
+import cats.kernel.instances.boolean._
+
+trait DistributiveLatticeTests[A] extends LatticeTests[A] {
+  def laws: DistributiveLatticeLaws[A]
+
+  def distributiveLattice(implicit arbA: Arbitrary[A], eqA: Eq[A]): RuleSet =
+    new DefaultRuleSet(
+      "distributiveLattice",
+      Some(lattice),
+      "distributiveLattice distribute" -> forAll(laws.distributive _)
+    )
+}
+
+object DistributiveLatticeTests {
+  def apply[A : DistributiveLattice]: DistributiveLatticeTests[A] =
+    new DistributiveLatticeTests[A] { def laws: DistributiveLatticeLaws[A] = DistributiveLatticeLaws[A] }
+}
diff --git a/laws/src/main/scala/algebra/laws/discipline/FieldTests.scala b/laws/src/main/scala/algebra/laws/discipline/FieldTests.scala
new file mode 100755
index 00000000..bb2a3a0d
--- /dev/null
+++ b/laws/src/main/scala/algebra/laws/discipline/FieldTests.scala
@@ -0,0 +1,23 @@
+package algebra
+package laws
+package discipline
+
+import algebra.ring._
+import org.scalacheck.Arbitrary
+
+trait FieldTests[A] extends CommutativeRingTests[A] with MultiplicativeCommutativeGroupTests[A] {
+  def laws: FieldLaws[A]
+
+  def field(implicit arbA: Arbitrary[A], eqA: Eq[A]): RuleSet =
+    new RuleSet {
+      def name = "field"
+      def parents = Seq(commutativeRing, multiplicativeCommutativeGroup)
+      def bases = Nil
+      def props = Nil
+    }
+}
+
+object FieldTests {
+  def apply[A: Field]: FieldTests[A] =
+    new FieldTests[A] { def laws: FieldLaws[A] = FieldLaws[A] }
+}
diff --git a/laws/src/main/scala/algebra/laws/discipline/JoinSemilatticeTests.scala b/laws/src/main/scala/algebra/laws/discipline/JoinSemilatticeTests.scala
new file mode 100644
index 00000000..8c061fd9
--- /dev/null
+++ b/laws/src/main/scala/algebra/laws/discipline/JoinSemilatticeTests.scala
@@ -0,0 +1,22 @@
+package algebra
+package laws
+package discipline
+
+import algebra.lattice.JoinSemilattice
+import cats.kernel.laws.discipline.SemilatticeTests
+import org.scalacheck.Arbitrary
+
+trait JoinSemilatticeTests[A] extends SemilatticeTests[A] {
+  def laws: JoinSemilatticeLaws[A]
+
+  def joinSemilattice(implicit arbA: Arbitrary[A], eqA: Eq[A]): RuleSet =
+    new DefaultRuleSet(
+      "joinSemilattice",
+      Some(semilattice)
+    )
+}
+
+object JoinSemilatticeTests {
+  def apply[A : JoinSemilattice]: JoinSemilatticeTests[A] =
+    new JoinSemilatticeTests[A] { def laws: JoinSemilatticeLaws[A] = JoinSemilatticeLaws[A] }
+}
diff --git a/laws/src/main/scala/algebra/laws/discipline/LatticeTests.scala b/laws/src/main/scala/algebra/laws/discipline/LatticeTests.scala
new file mode 100644
index 00000000..ad98254d
--- /dev/null
+++ b/laws/src/main/scala/algebra/laws/discipline/LatticeTests.scala
@@ -0,0 +1,27 @@
+package algebra
+package laws
+package discipline
+
+import algebra.lattice.Lattice
+import org.scalacheck.{Arbitrary, Prop}
+import Prop.forAll
+import cats.kernel.instances.boolean._
+
+trait LatticeTests[A] extends JoinSemilatticeTests[A] with MeetSemilatticeTests[A] {
+  def laws: LatticeLaws[A]
+
+  def lattice(implicit arbA: Arbitrary[A], eqA: Eq[A]): RuleSet =
+    new RuleSet {
+      def name: String = "lattice"
+      def bases: Seq[(String, RuleSet)] = Nil
+      def parents: Seq[RuleSet] = Seq(joinSemilattice, meetSemilattice)
+      def props: Seq[(String, Prop)] = Seq(
+        "lattice absorption" -> forAll(laws.absorption _)
+      )
+    }
+}
+
+object LatticeTests {
+  def apply[A : Lattice]: LatticeTests[A] =
+    new LatticeTests[A] { def laws: LatticeLaws[A] = LatticeLaws[A] }
+}
diff --git a/laws/src/main/scala/algebra/laws/discipline/MeetSemilatticeTests.scala b/laws/src/main/scala/algebra/laws/discipline/MeetSemilatticeTests.scala
new file mode 100644
index 00000000..ac75a6f4
--- /dev/null
+++ b/laws/src/main/scala/algebra/laws/discipline/MeetSemilatticeTests.scala
@@ -0,0 +1,22 @@
+package algebra
+package laws
+package discipline
+
+import algebra.lattice.MeetSemilattice
+import cats.kernel.laws.discipline.SemilatticeTests
+import org.scalacheck.Arbitrary
+
+trait MeetSemilatticeTests[A] extends SemilatticeTests[A] {
+  def laws: MeetSemilatticeLaws[A]
+
+  def meetSemilattice(implicit arbA: Arbitrary[A], eqA: Eq[A]): RuleSet =
+    new DefaultRuleSet(
+      "meetSemilattice",
+      Some(semilattice)
+    )
+}
+
+object MeetSemilatticeTests {
+  def apply[A : MeetSemilattice]: MeetSemilatticeTests[A] =
+    new MeetSemilatticeTests[A] { def laws: MeetSemilatticeLaws[A] = MeetSemilatticeLaws[A] }
+}
diff --git a/laws/src/main/scala/algebra/laws/discipline/MultiplicativeCommutativeGroupTests.scala b/laws/src/main/scala/algebra/laws/discipline/MultiplicativeCommutativeGroupTests.scala
new file mode 100755
index 00000000..08c2c860
--- /dev/null
+++ b/laws/src/main/scala/algebra/laws/discipline/MultiplicativeCommutativeGroupTests.scala
@@ -0,0 +1,22 @@
+package algebra
+package laws
+package discipline
+
+import algebra.ring._
+import org.scalacheck.Arbitrary
+
+trait MultiplicativeCommutativeGroupTests[A] extends MultiplicativeCommutativeMonoidTests[A] with MultiplicativeGroupTests[A] {
+  def laws: MultiplicativeCommutativeGroupLaws[A]
+
+  def multiplicativeCommutativeGroup(implicit arbA: Arbitrary[A], eqA: Eq[A]): CommutativeRuleSet =
+    new CommutativeRuleSet(
+      "multiplicativeCommutativeGroup",
+      multiplicativeGroup,
+      Some(multiplicativeCommutativeMonoid)
+    )
+}
+
+object MultiplicativeCommutativeGroupTests {
+  def apply[A: MultiplicativeCommutativeGroup]: MultiplicativeCommutativeGroupTests[A] =
+    new MultiplicativeCommutativeGroupTests[A] { def laws: MultiplicativeCommutativeGroupLaws[A] = MultiplicativeCommutativeGroupLaws[A] }
+}
diff --git a/laws/src/main/scala/algebra/laws/discipline/MultiplicativeCommutativeMonoidTests.scala b/laws/src/main/scala/algebra/laws/discipline/MultiplicativeCommutativeMonoidTests.scala
new file mode 100755
index 00000000..299ab95a
--- /dev/null
+++ b/laws/src/main/scala/algebra/laws/discipline/MultiplicativeCommutativeMonoidTests.scala
@@ -0,0 +1,22 @@
+package algebra
+package laws
+package discipline
+
+import algebra.ring._
+import org.scalacheck.Arbitrary
+
+trait MultiplicativeCommutativeMonoidTests[A] extends MultiplicativeCommutativeSemigroupTests[A] with MultiplicativeMonoidTests[A] {
+  def laws: MultiplicativeCommutativeMonoidLaws[A]
+
+  def multiplicativeCommutativeMonoid(implicit arbA: Arbitrary[A], eqA: Eq[A]): CommutativeRuleSet =
+    new CommutativeRuleSet(
+      "multiplicativeCommutativeMonoid",
+      multiplicativeMonoid,
+      Some(multiplicativeCommutativeSemigroup)
+    )
+}
+
+object MultiplicativeCommutativeMonoidTests {
+  def apply[A: MultiplicativeCommutativeMonoid]: MultiplicativeCommutativeMonoidTests[A] =
+    new MultiplicativeCommutativeMonoidTests[A] { def laws: MultiplicativeCommutativeMonoidLaws[A] = MultiplicativeCommutativeMonoidLaws[A] }
+}
diff --git a/laws/src/main/scala/algebra/laws/discipline/MultiplicativeCommutativeSemigroupTests.scala b/laws/src/main/scala/algebra/laws/discipline/MultiplicativeCommutativeSemigroupTests.scala
new file mode 100755
index 00000000..8830f7f4
--- /dev/null
+++ b/laws/src/main/scala/algebra/laws/discipline/MultiplicativeCommutativeSemigroupTests.scala
@@ -0,0 +1,25 @@
+package algebra
+package laws
+package discipline
+
+import algebra.ring._
+import org.scalacheck.{Arbitrary, Prop}
+import Prop._
+
+trait MultiplicativeCommutativeSemigroupTests[A] extends MultiplicativeSemigroupTests[A] with CommutativeTests {
+
+  def laws: MultiplicativeCommutativeSemigroupLaws[A]
+
+  def multiplicativeCommutativeSemigroup(implicit arbA: Arbitrary[A], eqA: Eq[A]): CommutativeRuleSet =
+    new CommutativeRuleSet(
+      "multiplicativeCommutativeSemigroup",
+      multiplicativeSemigroup,
+      None,
+      "times commutative" -> forAll(laws.timesCommutative _)
+    )
+}
+
+object MultiplicativeCommutativeSemigroupTests {
+  def apply[A: MultiplicativeCommutativeSemigroup]: MultiplicativeCommutativeSemigroupTests[A] =
+    new MultiplicativeCommutativeSemigroupTests[A] { def laws: MultiplicativeCommutativeSemigroupLaws[A] = MultiplicativeCommutativeSemigroupLaws[A] }
+}
diff --git a/laws/src/main/scala/algebra/laws/discipline/MultiplicativeGroupTests.scala b/laws/src/main/scala/algebra/laws/discipline/MultiplicativeGroupTests.scala
new file mode 100755
index 00000000..12bcaa39
--- /dev/null
+++ b/laws/src/main/scala/algebra/laws/discipline/MultiplicativeGroupTests.scala
@@ -0,0 +1,26 @@
+package algebra
+package laws
+package discipline
+
+import algebra.ring._
+import org.scalacheck.{Arbitrary, Prop}
+import Prop._
+
+trait MultiplicativeGroupTests[A] extends MultiplicativeMonoidTests[A] {
+
+  def laws: MultiplicativeGroupLaws[A]
+
+  def multiplicativeGroup(implicit arbA: Arbitrary[A], eqA: Eq[A]): RuleSet =
+    new DefaultRuleSet(
+      "multiplicativeGroup",
+      Some(multiplicativeMonoid),
+      "left reciprocal" -> forAll(laws.leftReciprocal _),
+      "right reciprocal" -> forAll(laws.rightReciprocal _),
+      "consistent div" -> forAll(laws.consistentDiv _)
+    )
+}
+
+object MultiplicativeGroupTests {
+  def apply[A: MultiplicativeGroup]: MultiplicativeGroupTests[A] =
+    new MultiplicativeGroupTests[A] { def laws: MultiplicativeGroupLaws[A] = MultiplicativeGroupLaws[A] }
+}
diff --git a/laws/src/main/scala/algebra/laws/discipline/MultiplicativeMonoidTests.scala b/laws/src/main/scala/algebra/laws/discipline/MultiplicativeMonoidTests.scala
new file mode 100755
index 00000000..0391aeef
--- /dev/null
+++ b/laws/src/main/scala/algebra/laws/discipline/MultiplicativeMonoidTests.scala
@@ -0,0 +1,29 @@
+package algebra
+package laws
+package discipline
+
+import algebra.ring._
+import org.scalacheck.{Arbitrary, Prop}
+import Prop._
+import cats.kernel.instances.boolean._
+
+trait MultiplicativeMonoidTests[A] extends MultiplicativeSemigroupTests[A] {
+
+  def laws: MultiplicativeMonoidLaws[A]
+
+  def multiplicativeMonoid(implicit arbA: Arbitrary[A], eqA: Eq[A]): RuleSet =
+    new DefaultRuleSet(
+      "multiplicativeMonoid",
+      Some(multiplicativeSemigroup),
+      "left one" -> forAll(laws.leftOne _),
+      "right one" -> forAll(laws.rightOne _),
+      "pow0" -> forAll(laws.pow0 _),
+      "product" -> laws.product,
+      "isOne" -> forAll((a: A) => laws.isOne(a, eqA))
+    )
+}
+
+object MultiplicativeMonoidTests {
+  def apply[A: MultiplicativeMonoid]: MultiplicativeMonoidTests[A] =
+    new MultiplicativeMonoidTests[A] { def laws: MultiplicativeMonoidLaws[A] = MultiplicativeMonoidLaws[A] }
+}
diff --git a/laws/src/main/scala/algebra/laws/discipline/MultiplicativeSemigroupTests.scala b/laws/src/main/scala/algebra/laws/discipline/MultiplicativeSemigroupTests.scala
new file mode 100755
index 00000000..22ffa270
--- /dev/null
+++ b/laws/src/main/scala/algebra/laws/discipline/MultiplicativeSemigroupTests.scala
@@ -0,0 +1,30 @@
+package algebra
+package laws
+package discipline
+
+import algebra.ring._
+import org.scalacheck.{Arbitrary, Prop}
+import org.typelevel.discipline.Laws
+import Prop._
+import cats.kernel.instances.option._
+
+trait MultiplicativeSemigroupTests[A] extends Laws {
+  def laws: MultiplicativeSemigroupLaws[A]
+
+  def multiplicativeSemigroup(implicit arbA: Arbitrary[A], eqA: Eq[A]): RuleSet =
+    new DefaultRuleSet(
+      "multiplicativeSemigroup",
+      None,
+      "times associative" -> forAll(laws.timesAssociative _),
+      "pow1" -> forAll(laws.pow1 _),
+      "pow2" -> forAll(laws.pow2 _),
+      "pow3" -> forAll(laws.pow3 _),
+      "tryProduct" -> forAll(laws.tryProduct _)
+    )
+
+}
+
+object MultiplicativeSemigroupTests {
+  def apply[A: MultiplicativeSemigroup]: MultiplicativeSemigroupTests[A] =
+    new MultiplicativeSemigroupTests[A] { def laws: MultiplicativeSemigroupLaws[A] = MultiplicativeSemigroupLaws[A] }
+}
diff --git a/laws/src/main/scala/algebra/laws/discipline/RigTests.scala b/laws/src/main/scala/algebra/laws/discipline/RigTests.scala
new file mode 100755
index 00000000..4883e06d
--- /dev/null
+++ b/laws/src/main/scala/algebra/laws/discipline/RigTests.scala
@@ -0,0 +1,23 @@
+package algebra
+package laws
+package discipline
+
+import algebra.ring._
+import org.scalacheck.Arbitrary
+
+trait RigTests[A] extends SemiringTests[A] with MultiplicativeMonoidTests[A] {
+  def laws: RigLaws[A]
+
+  def rig(implicit arbA: Arbitrary[A], eqA: Eq[A]): RingRuleSet =
+    new RingRuleSet(
+      "rig",
+      additiveCommutativeMonoid,
+      multiplicativeMonoid,
+      Seq(semiring)
+    )
+}
+
+object RigTests {
+  def apply[A: Rig]: RigTests[A] =
+    new RigTests[A] { def laws: RigLaws[A] = RigLaws[A] }
+}
diff --git a/laws/src/main/scala/algebra/laws/discipline/RingTests.scala b/laws/src/main/scala/algebra/laws/discipline/RingTests.scala
new file mode 100755
index 00000000..209a3456
--- /dev/null
+++ b/laws/src/main/scala/algebra/laws/discipline/RingTests.scala
@@ -0,0 +1,23 @@
+package algebra.laws.discipline
+
+import algebra.laws.RingLaws
+import algebra.ring.Ring
+import cats.kernel.Eq
+import org.scalacheck.Arbitrary
+
+trait RingTests[A] extends RigTests[A] with RngTests[A] {
+  def laws: RingLaws[A]
+
+  def ring(implicit arbA: Arbitrary[A], eqA: Eq[A]): RingRuleSet =
+    new RingRuleSet(
+      "ring",
+      additiveCommutativeGroup,
+      multiplicativeMonoid,
+      Seq(rig, rng)
+    )
+}
+
+object RingTests {
+  def apply[A: Ring]: RingTests[A] =
+    new RingTests[A] { def laws: RingLaws[A] = RingLaws[A] }
+}
diff --git a/laws/src/main/scala/algebra/laws/discipline/RngTests.scala b/laws/src/main/scala/algebra/laws/discipline/RngTests.scala
new file mode 100755
index 00000000..2e766071
--- /dev/null
+++ b/laws/src/main/scala/algebra/laws/discipline/RngTests.scala
@@ -0,0 +1,23 @@
+package algebra
+package laws
+package discipline
+
+import algebra.ring._
+import org.scalacheck.{Arbitrary}
+
+trait RngTests[A] extends SemiringTests[A] with AdditiveCommutativeGroupTests[A] {
+  def laws: RngLaws[A]
+
+  def rng(implicit arbA: Arbitrary[A], eqA: Eq[A]): RingRuleSet =
+    new RingRuleSet(
+      "rng",
+      additiveCommutativeGroup,
+      multiplicativeSemigroup,
+      Seq(semiring)
+    )
+}
+
+object RngTests {
+  def apply[A: Rng]: RngTests[A] =
+    new RngTests[A] { def laws: RngLaws[A] = RngLaws[A] }
+}
diff --git a/laws/src/main/scala/algebra/laws/discipline/SemiringTests.scala b/laws/src/main/scala/algebra/laws/discipline/SemiringTests.scala
new file mode 100755
index 00000000..08eb8421
--- /dev/null
+++ b/laws/src/main/scala/algebra/laws/discipline/SemiringTests.scala
@@ -0,0 +1,39 @@
+package algebra
+package laws
+package discipline
+
+import algebra.ring._
+import org.scalacheck.{Arbitrary, Prop}
+import Prop._
+
+trait SemiringTests[A] extends AdditiveCommutativeMonoidTests[A] with MultiplicativeSemigroupTests[A] {
+  def laws: SemiringLaws[A]
+
+  def semiring(implicit arbA: Arbitrary[A], eqA: Eq[A]): RingRuleSet =
+    new RingRuleSet(
+      "semiring",
+      additiveCommutativeMonoid,
+      multiplicativeSemigroup,
+      Nil,
+      "left distributive" -> forAll(laws.leftDistributive _),
+      "right distributive" -> forAll(laws.rightDistributive _),
+      "zero left annihilates" -> forAll(laws.zeroLeftAnnihilates _),
+      "zero right annihilates" -> forAll(laws.zeroRightAnnihilates _)
+    )
+
+  class RingRuleSet(
+    val name: String,
+    val additiveRuleSet: RuleSet,
+    val multiplicativeRuleSet: RuleSet,
+    val additionalParents: Seq[RingRuleSet],
+    val props: (String, Prop)*
+  ) extends RuleSet {
+    def parents = additionalParents ++ Seq(additiveRuleSet, multiplicativeRuleSet)
+    def bases = Nil
+ }
+}
+
+object SemiringTests {
+  def apply[A: Semiring]: SemiringTests[A] =
+    new SemiringTests[A] { def laws: SemiringLaws[A] = SemiringLaws[A] }
+}
diff --git a/laws/src/main/scala/algebra/laws/discipline/package.scala b/laws/src/main/scala/algebra/laws/discipline/package.scala
new file mode 100644
index 00000000..e7e904e3
--- /dev/null
+++ b/laws/src/main/scala/algebra/laws/discipline/package.scala
@@ -0,0 +1,11 @@
+package algebra.laws
+
+import cats.kernel.Eq
+import cats.kernel.laws.IsEq
+import org.scalacheck.Prop
+
+package object discipline {
+
+  implicit def catsLawsIsEqToProp[A: Eq](isEq: IsEq[A]): Prop =
+    cats.kernel.laws.discipline.catsLawsIsEqToProp[A](isEq)
+}
diff --git a/laws/src/test/scala/algebra/laws/LawTests.scala b/laws/src/test/scala/algebra/laws/LawTests.scala
index a0513502..ec909799 100644
--- a/laws/src/test/scala/algebra/laws/LawTests.scala
+++ b/laws/src/test/scala/algebra/laws/LawTests.scala
@@ -38,8 +38,8 @@ class LawTests extends FunSuite with Configuration with Discipline {
 
   implicit val byteLattice: Lattice[Byte] = ByteMinMaxLattice
   implicit val shortLattice: Lattice[Short] = ShortMinMaxLattice
-  implicit val intLattice: BoundedDistributiveLattice[Int] = IntMinMaxLattice
-  implicit val longLattice: BoundedDistributiveLattice[Long] = LongMinMaxLattice
+  implicit val intLattice: BoundedDistributiveLatticeLaws[Int] = IntMinMaxLattice
+  implicit val longLattice: BoundedDistributiveLatticeLaws[Long] = LongMinMaxLattice
 
   implicit def orderLaws[A: Cogen: Eq: Arbitrary] = OrderLaws[A]
   implicit def groupLaws[A: Eq: Arbitrary] = GroupLaws[A]
