diff --git a/.travis.yml b/.travis.yml
index 3cada132..3ae730ff 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -3,10 +3,10 @@ language: scala
 matrix:
   include:
     - scala: 2.10.5
-      script: ./sbt ++$TRAVIS_SCALA_VERSION clean test && ./sbt ++$TRAVIS_SCALA_VERSION core:mima-report-binary-issues
+      script: ./sbt ++$TRAVIS_SCALA_VERSION clean compile test && ./sbt ++$TRAVIS_SCALA_VERSION core:mima-report-binary-issues
 
     - scala: 2.11.7
-      script: ./sbt ++$TRAVIS_SCALA_VERSION clean test && ./sbt ++$TRAVIS_SCALA_VERSION core:mima-report-binary-issues
+      script: ./sbt ++$TRAVIS_SCALA_VERSION clean compile test && ./sbt ++$TRAVIS_SCALA_VERSION core:mima-report-binary-issues
 notifications:
   irc:
     channels:
diff --git a/build.sbt b/build.sbt
index 7bc6afb5..f80fc95c 100644
--- a/build.sbt
+++ b/build.sbt
@@ -5,9 +5,9 @@ import com.typesafe.tools.mima.plugin.MimaPlugin.mimaDefaultSettings
 import com.typesafe.tools.mima.plugin.MimaKeys.previousArtifact
 
 lazy val buildSettings = Seq(
-  organization := "org.spire-math",
-  scalaVersion := "2.11.7",
-  crossScalaVersions := Seq("2.10.5", "2.11.7")
+  organization := "org.typelevel",
+  scalaVersion := "2.11.8",
+  crossScalaVersions := Seq("2.10.6", "2.11.8")
 )
 
 lazy val commonSettings = Seq(
@@ -30,9 +30,13 @@ lazy val commonSettings = Seq(
     case Some((2, 11)) => Seq("-Ywarn-unused-import")
     case _             => Seq.empty
   }),
+  resolvers += Resolver.sonatypeRepo("public"),
   scalacOptions in (Compile, console) ~= (_ filterNot (_ == "-Ywarn-unused-import")),
   scalacOptions in (Test, console) := (scalacOptions in (Compile, console)).value,
-  scalaJSStage in Test := FastOptStage,
+  scalaJSStage in Global := FastOptStage,
+  scalaJSUseRhino := false,
+  requiresDOM := false,
+  jsEnv := NodeJSEnv().value,
   fork := false,
   parallelExecution in Test := false
 )
@@ -64,6 +68,7 @@ lazy val core = crossProject
   .settings(mimaDefaultSettings: _*)
   // TODO: update this to a published stable version, e.g. 0.4.0
   //.settings(previousArtifact := Some("org.spire-math" %% "algebra" % "0.3.1"))
+  .settings(libraryDependencies += "org.typelevel" %%% "cats-kernel" % "0.6.0-M2")
   .settings(algebraSettings: _*)
 
 lazy val coreJVM = core.jvm
@@ -107,13 +112,11 @@ lazy val laws = crossProject
   .dependsOn(core, ring, lattice, std, macros)
   .settings(moduleName := "algebra-laws")
   .settings(algebraSettings: _*)
-  .settings(
-    libraryDependencies ++= Seq(
-      "org.scalacheck" %%% "scalacheck" % "1.12.4",
-      "org.typelevel" %%% "discipline" % "0.4",
-      "org.scalatest" %%% "scalatest" % "3.0.0-M7" % "test"
-    )
-  )
+  .settings(libraryDependencies ++= Seq(
+    "org.typelevel" %%% "cats-kernel-laws" % "0.6.0-M2",
+    "org.scalacheck" %%% "scalacheck" % "1.12.4",
+    "org.typelevel" %%% "discipline" % "0.4",
+    "org.scalatest" %%% "scalatest" % "3.0.0-M7" % "test"))
 
 lazy val lawsJVM = laws.jvm 
 lazy val lawsJS = laws.js
diff --git a/core/src/main/scala/algebra/Band.scala b/core/src/main/scala/algebra/Band.scala
deleted file mode 100644
index 386e5a8c..00000000
--- a/core/src/main/scala/algebra/Band.scala
+++ /dev/null
@@ -1,18 +0,0 @@
-package algebra
-
-import scala.{specialized => sp}
-
-
-/**
- * Bands are semigroups whose operation
- * (i.e. combine) is also idempotent.
- */
-trait Band[@sp(Int, Long, Float, Double) A] extends Any with Semigroup[A]
-
-object Band {
-
-  /**
-   * Access an implicit `Band[A]`.
-   */
-  @inline final def apply[@sp(Int, Long, Float, Double) A](implicit ev: Band[A]): Band[A] = ev
-}
diff --git a/core/src/main/scala/algebra/BoundedSemilattice.scala b/core/src/main/scala/algebra/BoundedSemilattice.scala
deleted file mode 100644
index 048988e2..00000000
--- a/core/src/main/scala/algebra/BoundedSemilattice.scala
+++ /dev/null
@@ -1,13 +0,0 @@
-package algebra
-
-import scala.{specialized => sp}
-
-trait BoundedSemilattice[@sp(Int, Long, Float, Double) A] extends Any with Semilattice[A] with CommutativeMonoid[A]
-
-object BoundedSemilattice {
-
-  /**
-   * Access an implicit `BoundedSemilattice[A]`.
-   */
-  @inline final def apply[@sp(Int, Long, Float, Double) A](implicit ev: BoundedSemilattice[A]): BoundedSemilattice[A] = ev
-}
diff --git a/core/src/main/scala/algebra/CommutativeGroup.scala b/core/src/main/scala/algebra/CommutativeGroup.scala
deleted file mode 100644
index 9307d97b..00000000
--- a/core/src/main/scala/algebra/CommutativeGroup.scala
+++ /dev/null
@@ -1,17 +0,0 @@
-package algebra
-
-import scala.{ specialized => sp }
-
-/**
- * An abelian group is a group whose operation is commutative.
- */
-trait CommutativeGroup[@sp(Int, Long, Float, Double) A] extends Any with Group[A] with CommutativeMonoid[A]
-
-object CommutativeGroup extends GroupFunctions[CommutativeGroup] {
-
-  /**
-   * Access an implicit `CommutativeGroup[A]`.
-   */
-  @inline final def apply[A](implicit ev: CommutativeGroup[A]): CommutativeGroup[A] = ev
-}
-
diff --git a/core/src/main/scala/algebra/CommutativeMonoid.scala b/core/src/main/scala/algebra/CommutativeMonoid.scala
deleted file mode 100644
index 5591c75e..00000000
--- a/core/src/main/scala/algebra/CommutativeMonoid.scala
+++ /dev/null
@@ -1,17 +0,0 @@
-package algebra
-
-import scala.{ specialized => sp }
-
-/**
- * CommutativeMonoid represents a commutative monoid.
- *
- * A monoid is commutative if for all x and y, x |+| y === y |+| x.
- */
-trait CommutativeMonoid[@sp(Int, Long, Float, Double) A] extends Any with Monoid[A] with CommutativeSemigroup[A]
-
-object CommutativeMonoid extends MonoidFunctions[CommutativeMonoid] {
-  /**
-   * Access an implicit `CommutativeMonoid[A]`.
-   */
-  @inline final def apply[A](implicit ev: CommutativeMonoid[A]): CommutativeMonoid[A] = ev
-}
diff --git a/core/src/main/scala/algebra/CommutativeSemigroup.scala b/core/src/main/scala/algebra/CommutativeSemigroup.scala
deleted file mode 100644
index b6c3b202..00000000
--- a/core/src/main/scala/algebra/CommutativeSemigroup.scala
+++ /dev/null
@@ -1,18 +0,0 @@
-package algebra
-
-import scala.{ specialized => sp }
-
-/**
- * CommutativeSemigroup represents a commutative semigroup.
- *
- * A semigroup is commutative if for all x and y, x |+| y === y |+| x.
- */
-trait CommutativeSemigroup[@sp(Int, Long, Float, Double) A] extends Any with Semigroup[A]
-
-object CommutativeSemigroup extends SemigroupFunctions[CommutativeSemigroup] {
-
-  /**
-   * Access an implicit `CommutativeSemigroup[A]`.
-   */
-  @inline final def apply[A](implicit ev: CommutativeSemigroup[A]): CommutativeSemigroup[A] = ev
-}
diff --git a/core/src/main/scala/algebra/Eq.scala b/core/src/main/scala/algebra/Eq.scala
deleted file mode 100644
index 8db6f2b2..00000000
--- a/core/src/main/scala/algebra/Eq.scala
+++ /dev/null
@@ -1,138 +0,0 @@
-package algebra
-
-import scala.{specialized => sp}
-
-import scala.math.Equiv
-
-/**
- * A type class used to determine equality between 2 instances of the same
- * type. Any 2 instances `x` and `y` are equal if `eqv(x, y)` is `true`.
- * Moreover, `eqv` should form an equivalence relation.
- */
-trait Eq[@sp A] extends Any with Serializable { self =>
-
-  /**
-   * Returns `true` if `x` and `y` are equivalent, `false` otherwise.
-   */
-  def eqv(x: A, y: A): Boolean
-
-  /**
-   * Returns `false` if `x` and `y` are equivalent, `true` otherwise.
-   */
-  def neqv(x: A, y: A): Boolean = !eqv(x, y)
-
-  /**
-   * Constructs a new `Eq` instance for type `B` where 2 elements are
-   * equivalent iff `eqv(f(x), f(y))`.
-   */
-  def on[@sp B](f: B => A): Eq[B] =
-    new Eq[B] {
-      def eqv(x: B, y: B): Boolean = self.eqv(f(x), f(y))
-    }
-
-  /**
-   * Return an Eq that gives the result of the and of this and that
-   * note this is idempotent
-   */
-  def and(that: Eq[A]): Eq[A] =
-    new Eq[A] {
-      def eqv(x: A, y: A) = self.eqv(x, y) && that.eqv(x, y)
-    }
-  /**
-   * Return an Eq that gives the result of the or of this and that
-   * Note this is idempotent
-   */
-  def or(that: Eq[A]): Eq[A] =
-    new Eq[A] {
-      def eqv(x: A, y: A) = self.eqv(x, y) || that.eqv(x, y)
-    }
-}
-
-trait EqFunctions {
-  def eqv[@sp A](x: A, y: A)(implicit ev: Eq[A]): Boolean =
-    ev.eqv(x, y)
-
-  def neqv[@sp A](x: A, y: A)(implicit ev: Eq[A]): Boolean =
-    ev.neqv(x, y)
-}
-
-object Eq extends EqFunctions {
-
-  /**
-   * Access an implicit `Eq[A]`.
-   */
-  @inline final def apply[A](implicit ev: Eq[A]): Eq[A] = ev
-
-  /**
-   * Convert an implicit `Eq[B]` to an `Eq[A]` using the given
-   * function `f`.
-   */
-  def by[@sp A, @sp B](f: A => B)(implicit ev: Eq[B]): Eq[A] =
-    ev.on(f)
-
-  /**
-   * This gives compatibility with scala's Equiv trait
-   */
-  implicit def equiv[A](implicit ev: Eq[A]): Equiv[A] =
-    new Equiv[A] {
-      def equiv(a: A, b: A) = ev.eqv(a, b)
-    }
-
-  /**
-   * Create an `Eq` instance from an `eqv` implementation.
-   */
-  def instance[A](f: (A, A) => Boolean): Eq[A] =
-    new Eq[A] {
-      def eqv(x: A, y: A) = f(x, y)
-    }
-
-  /**
-   * An `Eq[A]` that delegates to universal equality (`==`).
-   *
-   * This can be useful for case classes, which have reasonable `equals`
-   * implementations
-   */
-  def fromUniversalEquals[A]: Eq[A] =
-    new Eq[A] {
-      def eqv(x: A, y: A) = x == y
-    }
-
-  /**
-   * Everything is the same
-   */
-  def allEqual[A]: Eq[A] = new Eq[A] {
-    def eqv(x: A, y: A) = true
-  }
-
-  /**
-   * This is a monoid that creates an Eq that
-   * checks that all equality checks pass
-   */
-  def allEqualBoundedSemilattice[A]: BoundedSemilattice[Eq[A]] = new BoundedSemilattice[Eq[A]] {
-    def empty = allEqual[A]
-    def combine(e1: Eq[A], e2: Eq[A]): Eq[A] = e1.and(e2)
-    override def combineAllOption(es: TraversableOnce[Eq[A]]): Option[Eq[A]] =
-      if (es.isEmpty) None
-      else {
-        val materialized = es.toVector
-        Some(new Eq[A] {
-          def eqv(x: A, y: A) = materialized.forall(_.eqv(x, y))
-        })
-      }
-  }
-  /**
-   * This is a monoid that creates an Eq that
-   * checks that at least one equality check passes
-   */
-  def anyEqualSemilattice[A]: Semilattice[Eq[A]] = new Semilattice[Eq[A]] {
-    def combine(e1: Eq[A], e2: Eq[A]): Eq[A] = e1.or(e2)
-    override def combineAllOption(es: TraversableOnce[Eq[A]]): Option[Eq[A]] =
-      if (es.isEmpty) None
-      else {
-        val materialized = es.toVector
-        Some(new Eq[A] {
-          def eqv(x: A, y: A) = materialized.exists(_.eqv(x, y))
-        })
-      }
-  }
-}
diff --git a/core/src/main/scala/algebra/Group.scala b/core/src/main/scala/algebra/Group.scala
deleted file mode 100644
index 410252f7..00000000
--- a/core/src/main/scala/algebra/Group.scala
+++ /dev/null
@@ -1,48 +0,0 @@
-package algebra
-
-import scala.{ specialized => sp }
-
-/**
- * A group is a monoid where each element has an inverse.
- */
-trait Group[@sp(Int, Long, Float, Double) A] extends Any with Monoid[A] {
-
-  /**
-   * Find the inverse of `a`.
-   *
-   * `combine(a, inverse(a))` = `combine(inverse(a), a)` = `empty`.
-   */
-  def inverse(a: A): A
-
-  /**
-   * Remove the element `b` from `a`.
-   *
-   * Equivalent to `combine(a, inverse(a))`
-   */
-  def remove(a: A, b: A): A = combine(a, inverse(b))
-
-  /**
-   * Return `a` appended to itself `n` times. If `n` is negative, then
-   * this returns `inverse(a)` appended to itself `n` times.
-   */
-  override def combineN(a: A, n: Int): A =
-    if (n > 0) repeatedCombineN(a, n)
-    else if (n == 0) empty
-    else if (n == Int.MinValue) combineN(inverse(combine(a, a)), 1073741824)
-    else repeatedCombineN(inverse(a), -n)
-}
-
-trait GroupFunctions[G[T] <: Group[T]] extends MonoidFunctions[Group] {
-  def inverse[@sp(Int, Long, Float, Double) A](a: A)(implicit ev: G[A]): A =
-    ev.inverse(a)
-  def remove[@sp(Int, Long, Float, Double) A](x: A, y: A)(implicit ev: G[A]): A =
-    ev.remove(x, y)
-}
-
-object Group extends GroupFunctions[Group] {
-
-  /**
-   * Access an implicit `Group[A]`.
-   */
-  @inline final def apply[A](implicit ev: Group[A]): Group[A] = ev
-}
diff --git a/core/src/main/scala/algebra/Monoid.scala b/core/src/main/scala/algebra/Monoid.scala
deleted file mode 100644
index d321e0a4..00000000
--- a/core/src/main/scala/algebra/Monoid.scala
+++ /dev/null
@@ -1,52 +0,0 @@
-package algebra
-
-import scala.{ specialized => sp }
-
-/**
- * A monoid is a semigroup with an identity. A monoid is a specialization of a
- * semigroup, so its operation must be associative. Additionally,
- * `combine(x, empty) == combine(empty, x) == x`. For example, if we have `Monoid[String]`,
- * with `combine` as string concatenation, then `empty = ""`.
- */
-trait Monoid[@sp(Int, Long, Float, Double) A] extends Any with Semigroup[A] {
-
-  /**
-   * Return the identity element for this monoid.
-   */
-  def empty: A
-
-  /**
-   * Tests if `a` is the identity.
-   */
-  def isEmpty(a: A)(implicit ev: Eq[A]) = ev.eqv(a, empty)
-
-  /**
-   * Return `a` appended to itself `n` times.
-   */
-  override def combineN(a: A, n: Int): A =
-    if (n < 0) throw new IllegalArgumentException("Repeated combining for monoids must have n >= 0")
-    else if (n == 0) empty
-    else repeatedCombineN(a, n)
-
-  /**
-   * Given a sequence of `as`, sum them using the monoid and return the total.
-   */
-  def combineAll(as: TraversableOnce[A]): A =
-    as.foldLeft(empty)(combine)
-}
-
-trait MonoidFunctions[M[T] <: Monoid[T]] extends SemigroupFunctions[M] {
-  def empty[@sp(Int, Long, Float, Double) A](implicit ev: M[A]): A =
-    ev.empty
-
-  def combineAll[@sp(Int, Long, Float, Double) A](as: TraversableOnce[A])(implicit ev: M[A]): A =
-    ev.combineAll(as)
-}
-
-object Monoid extends MonoidFunctions[Monoid] {
-
-  /**
-   * Access an implicit `Monoid[A]`.
-   */
-  @inline final def apply[A](implicit ev: Monoid[A]): Monoid[A] = ev
-}
diff --git a/core/src/main/scala/algebra/Order.scala b/core/src/main/scala/algebra/Order.scala
deleted file mode 100644
index bc1fc86c..00000000
--- a/core/src/main/scala/algebra/Order.scala
+++ /dev/null
@@ -1,209 +0,0 @@
-package algebra
-
-import scala.{specialized => sp}
-
-/**
- * The `Order` type class is used to define a total ordering on some type `A`.
- * An order is defined by a relation <=, which obeys the following laws:
- *
- * - either x <= y or y <= x (totality)
- * - if x <= y and y <= x, then x == y (antisymmetry)
- * - if x <= y and y <= z, then x <= z (transitivity)
- *
- * The truth table for compare is defined as follows:
- *
- * x <= y    x >= y      Int
- * true      true        = 0     (corresponds to x == y)
- * true      false       < 0     (corresponds to x < y)
- * false     true        > 0     (corresponds to x > y)
- *
- * By the totality law, x <= y and y <= x cannot be both false.
- */
-trait Order[@sp A] extends Any with PartialOrder[A] { self =>
-
-  /**
-   * Result of comparing `x` with `y`. Returns an Int whose sign is:
-   * - negative iff `x < y`
-   * - zero     iff `x = y`
-   * - positive iff `x > y`
-   */
-  def compare(x: A, y: A): Int
-
-  def partialCompare(x: A, y: A): Double = compare(x, y).toDouble
-
-  /**
-   * If x <= y, return x, else return y.
-   */
-  def min(x: A, y: A): A = if (lt(x, y)) x else y
-
-  /**
-   * If x >= y, return x, else return y.
-   */
-  def max(x: A, y: A): A = if (gt(x, y)) x else y
-
-  /**
-   * Defines an order on `B` by mapping `B` to `A` using `f` and using `A`s
-   * order to order `B`.
-   */
-  override def on[@sp B](f: B => A): Order[B] =
-    new Order[B] {
-      def compare(x: B, y: B): Int = self.compare(f(x), f(y))
-    }
-
-  /**
-   * Defines an ordering on `A` where all arrows switch direction.
-   */
-  override def reverse: Order[A] =
-    new Order[A] {
-      def compare(x: A, y: A): Int = self.compare(y, x)
-
-      override def reverse: Order[A] = self
-    }
-
-  // The following may be overridden for performance:
-
-  /**
-   * Returns true if `x` = `y`, false otherwise.
-   */
-  override def eqv(x: A, y: A): Boolean =
-    compare(x, y) == 0
-
-  /**
-   * Returns true if `x` != `y`, false otherwise.
-   */
-  override def neqv(x: A, y: A): Boolean =
-    compare(x, y) != 0
-
-  /**
-   * Returns true if `x` <= `y`, false otherwise.
-   */
-  override def lteqv(x: A, y: A): Boolean =
-    compare(x, y) <= 0
-
-  /**
-   * Returns true if `x` < `y`, false otherwise.
-   */
-  override def lt(x: A, y: A): Boolean =
-    compare(x, y) < 0
-
-  /**
-   * Returns true if `x` >= `y`, false otherwise.
-   */
-  override def gteqv(x: A, y: A): Boolean =
-    compare(x, y) >= 0
-
-  /**
-   * Returns true if `x` > `y`, false otherwise.
-   */
-  override def gt(x: A, y: A): Boolean =
-    compare(x, y) > 0
-
-  /**
-   * Returns a new `Order[A]` instance that first compares by the original
-   * `Order` instance and uses the provided `Order` instance to "break ties".
-   *
-   * That is, `x.whenEqual(y)` creates an `Order` that first orders by `x` and
-   * then (if two elements are equal) falls back to `y` for the comparison.
-   */
-  def whenEqual(o: Order[A]): Order[A] = new Order[A] {
-    def compare(x: A, y: A) = {
-      val c = self.compare(x, y)
-      if (c == 0) o.compare(x, y)
-      else c
-    }
-  }
-
-  /**
-   * Convert a `Order[A]` to a `scala.math.Ordering[A]`
-   * instance.
-   */
-  def toOrdering: Ordering[A] = new Ordering[A] {
-    def compare(x: A, y: A): Int = self.compare(x, y)
-  }
-}
-
-trait OrderFunctions {
-  def compare[@sp A](x: A, y: A)(implicit ev: Order[A]): Int =
-    ev.compare(x, y)
-
-  def eqv[@sp A](x: A, y: A)(implicit ev: Order[A]): Boolean =
-    ev.eqv(x, y)
-  def neqv[@sp A](x: A, y: A)(implicit ev: Order[A]): Boolean =
-    ev.neqv(x, y)
-  def gt[@sp A](x: A, y: A)(implicit ev: Order[A]): Boolean =
-    ev.gt(x, y)
-  def gteqv[@sp A](x: A, y: A)(implicit ev: Order[A]): Boolean =
-    ev.gteqv(x, y)
-  def lt[@sp A](x: A, y: A)(implicit ev: Order[A]): Boolean =
-    ev.lt(x, y)
-  def lteqv[@sp A](x: A, y: A)(implicit ev: Order[A]): Boolean =
-    ev.lteqv(x, y)
-
-  def min[@sp A](x: A, y: A)(implicit ev: Order[A]): A =
-    ev.min(x, y)
-  def max[@sp A](x: A, y: A)(implicit ev: Order[A]): A =
-    ev.max(x, y)
-}
-
-object Order extends OrderFunctions {
-
-  /**
-   * Access an implicit `Eq[A]`.
-   */
-  @inline final def apply[A](implicit ev: Order[A]) = ev
-
-  /**
-   * Convert an implicit `Order[A]` to an `Order[B]` using the given
-   * function `f`.
-   */
-  def by[@sp A, @sp B](f: A => B)(implicit ev: Order[B]): Order[A] =
-    ev.on(f)
-
-  /**
-   * Define an `Order[A]` using the given function `f`.
-   */
-  def from[@sp A](f: (A, A) => Int): Order[A] =
-    new Order[A] {
-      def compare(x: A, y: A) = f(x, y)
-    }
-
-  /**
-   * Implicitly convert a `Order[A]` to a `scala.math.Ordering[A]`
-   * instance.
-   */
-  implicit def ordering[A](implicit ev: Order[A]): Ordering[A] =
-    ev.toOrdering
-
-  /**
-   * An `Order` instance that considers all `A` instances to be equal.
-   */
-  def allEqual[A]: Order[A] = new Order[A] {
-    def compare(x: A, y: A): Int = 0
-  }
-
-
-  /**
-   * A `Monoid[Order[A]]` can be generated for all `A` with the following
-   * properties:
-   *
-   * `empty` returns a trivial `Order[A]` which considers all `A` instances to
-   * be equal.
-   *
-   * `combine(x: Order[A], y: Order[A])` creates an `Order[A]` that first
-   * orders by `x` and then (if two elements are equal) falls back to `y`.
-   *
-   * @see [[Order.whenEqual]]
-   */
-  def whenEqualMonoid[A]: Monoid[Order[A]] =
-    new Monoid[Order[A]] {
-      val empty: Order[A] = allEqual[A]
-
-      def combine(x: Order[A], y: Order[A]): Order[A] = x whenEqual y
-    }
-
-  def fromOrdering[A](implicit ev: Ordering[A]): Order[A] = new Order[A] {
-    def compare(x: A, y: A): Int = ev.compare(x, y)
-
-    override def toOrdering: Ordering[A] = ev
-  }
-}
diff --git a/core/src/main/scala/algebra/PartialOrder.scala b/core/src/main/scala/algebra/PartialOrder.scala
deleted file mode 100644
index 0a3c902f..00000000
--- a/core/src/main/scala/algebra/PartialOrder.scala
+++ /dev/null
@@ -1,169 +0,0 @@
-package algebra
-
-import scala.{specialized => sp}
-
-/**
- * The `PartialOrder` type class is used to define a partial ordering on some type `A`.
- * 
- * A partial order is defined by a relation <=, which obeys the following laws:
- * 
- * - x <= x (reflexivity)
- * - if x <= y and y <= x, then x = y (anti-symmetry)
- * - if x <= y and y <= z, then x <= z (transitivity)
- * 
- * To compute both <= and >= at the same time, we use a Double number
- * to encode the result of the comparisons x <= y and x >= y.
- * The truth table is defined as follows:
- * 
- * x <= y    x >= y      Double
- * true      true        = 0.0     (corresponds to x = y)
- * false     false       = NaN     (x and y cannot be compared)
- * true      false       = -1.0    (corresponds to x < y)
- * false     true        = 1.0     (corresponds to x > y)
- */
-trait PartialOrder[@sp A] extends Any with Eq[A] { self =>
-
-  /**
-   * Result of comparing `x` with `y`. Returns NaN if operands are not
-   * comparable. If operands are comparable, returns a Double whose
-   * sign is:
-   * - negative iff `x < y`
-   * - zero     iff `x = y`
-   * - positive iff `x > y`
-   */
-  def partialCompare(x: A, y: A): Double
-
-  /**
-   * Result of comparing `x` with `y`. Returns None if operands are
-   * not comparable. If operands are comparable, returns Some[Int]
-   * where the Int sign is:
-   * - negative iff `x < y`
-   * - zero     iff `x = y`
-   * - positive iff `x > y`
-   */  
-  def tryCompare(x: A, y: A): Option[Int] = {
-    val c = partialCompare(x, y)
-    if (c.isNaN) None else Some(c.signum)
-  }
-
-  /**
-   * Returns Some(x) if x <= y, Some(y) if x > y, otherwise None.
-   */
-  def pmin(x: A, y: A): Option[A] = {
-    val c = partialCompare(x, y)
-    if (c <= 0) Some(x)
-    else if (c > 0) Some(y)
-    else None
-  }
-
-  /**
-   * Returns Some(x) if x >= y, Some(y) if x < y, otherwise None.
-   */
-  def pmax(x: A, y: A): Option[A] = {
-    val c = partialCompare(x, y)
-    if (c >= 0)  Some(x)
-    else if (c < 0) Some(y)
-    else None
-  }
-
-  /**
-   * Defines a partial order on `B` by mapping `B` to `A` using `f`
-   * and using `A`s order to order `B`.
-   */
-  override def on[@sp B](f: B => A): PartialOrder[B] =
-    new PartialOrder[B] {
-      def partialCompare(x: B, y: B): Double = self.partialCompare(f(x), f(y))
-    }
-
-  /**
-   * Defines a partial order on `A` where all arrows switch direction.
-   */
-  def reverse: PartialOrder[A] =
-    new PartialOrder[A] {
-      def partialCompare(x: A, y: A): Double = self.partialCompare(y, x)
-    }
-
-  // The following may be overridden for performance:
-
-  /**
-   * Returns true if `x` = `y`, false otherwise.
-   */
-  def eqv(x: A, y: A): Boolean = partialCompare(x, y) == 0
-
-  /**
-   * Returns true if `x` <= `y`, false otherwise.
-   */
-  def lteqv(x: A, y: A): Boolean = partialCompare(x, y) <= 0
-
-  /**
-   * Returns true if `x` < `y`, false otherwise.
-   */
-  def lt(x: A, y: A): Boolean = partialCompare(x, y) < 0
-
-  /**
-   * Returns true if `x` >= `y`, false otherwise.
-   */
-  def gteqv(x: A, y: A): Boolean = partialCompare(x, y) >= 0
-
-  /**
-   * Returns true if `x` > `y`, false otherwise.
-   */
-  def gt(x: A, y: A): Boolean = partialCompare(x, y) > 0
-}
-
-trait PartialOrderFunctions {
-
-  def partialCompare[@sp A](x: A, y: A)(implicit ev: PartialOrder[A]): Double =
-    ev.partialCompare(x, y)
-  def tryCompare[@sp A](x: A, y: A)(implicit ev: PartialOrder[A]): Option[Int] =
-    ev.tryCompare(x, y)
-
-  def pmin[@sp A](x: A, y: A)(implicit ev: PartialOrder[A]): Option[A] =
-    ev.pmin(x, y)
-  def pmax[@sp A](x: A, y: A)(implicit ev: PartialOrder[A]): Option[A] =
-    ev.pmax(x, y)
-
-  def eqv[@sp A](x: A, y: A)(implicit ev: PartialOrder[A]): Boolean =
-    ev.eqv(x, y)
-  def lteqv[@sp A](x: A, y: A)(implicit ev: PartialOrder[A]): Boolean =
-    ev.lteqv(x, y)
-  def lt[@sp A](x: A, y: A)(implicit ev: PartialOrder[A]): Boolean =
-    ev.lt(x, y)
-  def gteqv[@sp A](x: A, y: A)(implicit ev: PartialOrder[A]): Boolean =
-    ev.gteqv(x, y)
-  def gt[@sp A](x: A, y: A)(implicit ev: PartialOrder[A]): Boolean =
-    ev.gt(x, y)
-}
-
-object PartialOrder extends PartialOrderFunctions {
-
-  /**
-   * Access an implicit `Eq[A]`.
-   */
-  @inline final def apply[A](implicit ev: PartialOrder[A]) = ev
-
-  /**
-   * Convert an implicit `PartialOrder[A]` to an `PartialOrder[B]`
-   * using the given function `f`.
-   */
-  def by[@sp A, @sp B](f: A => B)(implicit ev: PartialOrder[B]): PartialOrder[A] =
-    ev.on(f)
-
-  /**
-   * Define a `PartialOrder[A]` using the given function `f`.
-   */
-  def from[@sp A](f: (A, A) => Double): PartialOrder[A] =
-    new PartialOrder[A] {
-      def partialCompare(x: A, y: A) = f(x, y)
-    }
-
-  /**
-   * Implicitly convert a `PartialOrder[A]` to a
-   * `scala.math.PartialOrdering[A]` instance.
-   */
-  implicit def partialOrdering[A](implicit ev: PartialOrder[A]): PartialOrdering[A] =
-    new PartialOrdering[A] {
-      def tryCompare(x: A, y: A): Option[Int] = ev.tryCompare(x, y)
-      def lteq(x: A, y: A): Boolean = ev.lteqv(x, y)
-    }
-}
diff --git a/core/src/main/scala/algebra/Semigroup.scala b/core/src/main/scala/algebra/Semigroup.scala
deleted file mode 100644
index 6838f67a..00000000
--- a/core/src/main/scala/algebra/Semigroup.scala
+++ /dev/null
@@ -1,79 +0,0 @@
-package algebra
-
-import scala.{ specialized => sp }
-import scala.annotation.{ switch, tailrec }
-
-/**
- * A semigroup is any set `A` with an associative operation (`combine`).
- */
-trait Semigroup[@sp(Int, Long, Float, Double) A] extends Any with Serializable {
-
-  /**
-   * Associative operation taking which combines two values.
-   */
-  def combine(x: A, y: A): A
-
-  /**
-   * Return `a` combined with itself `n` times.
-   */
-  def combineN(a: A, n: Int): A =
-    if (n <= 0) throw new IllegalArgumentException("Repeated combining for semigroups must have n > 0")
-    else repeatedCombineN(a, n)
-
-  /**
-   * Return `a` combined with itself more than once.
-   */
-  protected[this] def repeatedCombineN(a: A, n: Int): A = {
-    @tailrec def loop(b: A, k: Int, extra: A): A =
-      if (k == 1) combine(b, extra) else {
-        val x = if ((k & 1) == 1) combine(b, extra) else extra
-        loop(combine(b, b), k >>> 1, x)
-      }
-    if (n == 1) a else loop(a, n - 1, a)
-  }
-
-  /**
-   * Given a sequence of `as`, combine them and return the total.
-   *
-   * If the sequence is empty, returns None. Otherwise, returns Some(total).
-   */
-  def combineAllOption(as: TraversableOnce[A]): Option[A] =
-    as.reduceOption(combine)
-}
-
-trait SemigroupFunctions[S[T] <: Semigroup[T]] {
-  def combine[@sp(Int, Long, Float, Double) A](x: A, y: A)(implicit ev: S[A]): A =
-    ev.combine(x, y)
-
-  def maybeCombine[@sp(Int, Long, Float, Double) A](ox: Option[A], y: A)(implicit ev: S[A]): A =
-    ox match {
-      case Some(x) => ev.combine(x, y)
-      case None => y
-    }
-
-  def maybeCombine[@sp(Int, Long, Float, Double) A](x: A, oy: Option[A])(implicit ev: S[A]): A =
-    oy match {
-      case Some(y) => ev.combine(x, y)
-      case None => x
-    }
-
-  def isCommutative[A](implicit ev: S[A]): Boolean =
-    ev.isInstanceOf[CommutativeSemigroup[_]]
-
-  def isIdempotent[A](implicit ev: S[A]): Boolean =
-    ev.isInstanceOf[Band[_]]
-
-  def combineN[@sp(Int, Long, Float, Double) A](a: A, n: Int)(implicit ev: S[A]): A =
-    ev.combineN(a, n)
-
-  def combineAllOption[A](as: TraversableOnce[A])(implicit ev: S[A]): Option[A] =
-    ev.combineAllOption(as)
-}
-
-object Semigroup extends SemigroupFunctions[Semigroup] {
-
-  /**
-   * Access an implicit `Semigroup[A]`.
-   */
-  @inline final def apply[A](implicit ev: Semigroup[A]) = ev
-}
diff --git a/core/src/main/scala/algebra/Semilattice.scala b/core/src/main/scala/algebra/Semilattice.scala
deleted file mode 100644
index ca5b443b..00000000
--- a/core/src/main/scala/algebra/Semilattice.scala
+++ /dev/null
@@ -1,62 +0,0 @@
-package algebra
-
-import scala.{specialized => sp}
-
-/**
- * Semilattices are commutative semigroups whose operation
- * (i.e. combine) is also idempotent.
- */
-trait Semilattice[@sp(Int, Long, Float, Double) A] extends Any
-  with Band[A]
-  with CommutativeSemigroup[A] { self =>
-
-  /**
-   * Given Eq[A], return a PartialOrder[A] using the `combine`
-   * operator to determine the partial ordering. This method assumes
-   * `combine` functions as `meet` (that is, as a lower bound).
-   *
-   * This method returns:
-   *
-   *    0.0 if x = y
-   *   -1.0 if x = combine(x, y)
-   *    1.0 if y = combine(x, y)
-   *    NaN otherwise
-   */
-  def asMeetPartialOrder(implicit ev: Eq[A]): PartialOrder[A] =
-    new PartialOrder[A] {
-      def partialCompare(x: A, y: A): Double =
-        if (ev.eqv(x, y)) 0.0 else {
-          val z = self.combine(x, y)
-          if (ev.eqv(x, z)) -1.0 else if (ev.eqv(y, z)) 1.0 else Double.NaN
-        }
-    }
-
-  /**
-   * Given Eq[A], return a PartialOrder[A] using the `combine`
-   * operator to determine the partial ordering. This method assumes
-   * `combine` functions as `join` (that is, as an upper bound).
-   *
-   * This method returns:
-   *
-   *    0.0 if x = y
-   *   -1.0 if y = combine(x, y)
-   *    1.0 if x = combine(x, y)
-   *    NaN otherwise
-   */
-  def asJoinPartialOrder(implicit ev: Eq[A]): PartialOrder[A] =
-    new PartialOrder[A] {
-      def partialCompare(x: A, y: A): Double =
-        if (ev.eqv(x, y)) 0.0 else {
-          val z = self.combine(x, y)
-          if (ev.eqv(y, z)) -1.0 else if (ev.eqv(x, z)) 1.0 else Double.NaN
-        }
-    }
-}
-
-object Semilattice {
-
-  /**
-   * Access an implicit `Semilattice[A]`.
-   */
-  @inline final def apply[@sp(Int, Long, Float, Double) A](implicit ev: Semilattice[A]): Semilattice[A] = ev
-}
diff --git a/core/src/main/scala/algebra/package.scala b/core/src/main/scala/algebra/package.scala
index c4a8f038..0f720497 100644
--- a/core/src/main/scala/algebra/package.scala
+++ b/core/src/main/scala/algebra/package.scala
@@ -1,2 +1,38 @@
 package object algebra {
+
+  type Band[A] = cats.kernel.Band[A]
+  val Band = cats.kernel.Band
+
+  type BoundedSemilattice[A] = cats.kernel.BoundedSemilattice[A]
+  val BoundedSemilattice = cats.kernel.BoundedSemilattice
+
+  type CommutativeGroup[A] = cats.kernel.CommutativeGroup[A]
+  val CommutativeGroup = cats.kernel.CommutativeGroup
+
+  type CommutativeMonoid[A] = cats.kernel.CommutativeMonoid[A]
+  val CommutativeMonoid = cats.kernel.CommutativeMonoid
+
+  type CommutativeSemigroup[A] = cats.kernel.CommutativeSemigroup[A]
+  val CommutativeSemigroup = cats.kernel.CommutativeSemigroup
+
+  type Eq[A] = cats.kernel.Eq[A]
+  val Eq = cats.kernel.Eq
+
+  type Group[A] = cats.kernel.Group[A]
+  val Group = cats.kernel.Group
+
+  type Monoid[A] = cats.kernel.Monoid[A]
+  val Monoid = cats.kernel.Monoid
+
+  type Order[A] = cats.kernel.Order[A]
+  val Order = cats.kernel.Order
+
+  type PartialOrder[A] = cats.kernel.PartialOrder[A]
+  val PartialOrder = cats.kernel.PartialOrder
+
+  type Semigroup[A] = cats.kernel.Semigroup[A]
+  val Semigroup = cats.kernel.Semigroup
+
+  type Semilattice[A] = cats.kernel.Semilattice[A]
+  val Semilattice = cats.kernel.Semilattice
 }
diff --git a/laws/js/src/main/scala/algebra/laws/Platform.scala b/laws/js/src/main/scala/algebra/laws/Platform.scala
index 4c18fd91..4a018c71 100644
--- a/laws/js/src/main/scala/algebra/laws/Platform.scala
+++ b/laws/js/src/main/scala/algebra/laws/Platform.scala
@@ -1,12 +1,15 @@
 package algebra
 package laws
 
-import org.scalacheck.{Arbitrary, Prop}
+import org.scalacheck.Prop
 import org.scalacheck.Prop._
-import Prop.{False, Proof, Result}
+import Prop.{ Proof, Result }
 
 private[laws] object Platform {
 
+  final val isJvm = false
+  final val isJs = true
+
   // Scala-js does not implement the Serializable interface, so we just retuen true.
   @inline
   def serializable[M](m: M): (String, Prop) = "serializable" -> Prop { _ =>
diff --git a/laws/jvm/src/main/scala/algebra/laws/Platform.scala b/laws/jvm/src/main/scala/algebra/laws/Platform.scala
index 0c380844..6944ec68 100644
--- a/laws/jvm/src/main/scala/algebra/laws/Platform.scala
+++ b/laws/jvm/src/main/scala/algebra/laws/Platform.scala
@@ -1,12 +1,15 @@
 package algebra
 package laws
 
-import org.scalacheck.{Arbitrary, Prop}
+import org.scalacheck.Prop
 import org.scalacheck.Prop._
-import Prop.{False, Proof, Result}
 import scala.util.control.NonFatal
 
 private[laws] object Platform {
+
+  final val isJvm = true
+  final val isJs = false
+
   // Scala-js does not implement the Serializable interface, so the
   // real test is for JVM only.
   @inline
diff --git a/laws/shared/src/main/scala/algebra/laws/LatticeLaws.scala b/laws/shared/src/main/scala/algebra/laws/LatticeLaws.scala
index 2aa50014..925a19a2 100644
--- a/laws/shared/src/main/scala/algebra/laws/LatticeLaws.scala
+++ b/laws/shared/src/main/scala/algebra/laws/LatticeLaws.scala
@@ -3,8 +3,6 @@ package algebra.laws
 import algebra._
 import algebra.lattice._
 
-import org.typelevel.discipline.Laws
-
 import org.scalacheck.{Arbitrary, Prop}
 import org.scalacheck.Prop._
 
diff --git a/laws/shared/src/main/scala/algebra/laws/LogicLaws.scala b/laws/shared/src/main/scala/algebra/laws/LogicLaws.scala
index 959af1a7..5b20f0c4 100644
--- a/laws/shared/src/main/scala/algebra/laws/LogicLaws.scala
+++ b/laws/shared/src/main/scala/algebra/laws/LogicLaws.scala
@@ -3,8 +3,6 @@ package algebra.laws
 import algebra._
 import algebra.lattice.{Heyting, Bool, GenBool}
 
-import org.typelevel.discipline.Laws
-
 import org.scalacheck.{Arbitrary, Prop}
 import org.scalacheck.Prop._
 
diff --git a/laws/shared/src/main/scala/algebra/laws/RingLaws.scala b/laws/shared/src/main/scala/algebra/laws/RingLaws.scala
index ea1d3a69..e640e59c 100644
--- a/laws/shared/src/main/scala/algebra/laws/RingLaws.scala
+++ b/laws/shared/src/main/scala/algebra/laws/RingLaws.scala
@@ -3,7 +3,7 @@ package laws
 
 import algebra.ring._
 
-import org.typelevel.discipline.{Laws, Predicate}
+import org.typelevel.discipline.Predicate
 
 import org.scalacheck.{Arbitrary, Prop}
 import org.scalacheck.Arbitrary._
diff --git a/laws/shared/src/main/scala/algebra/laws/Rules.scala b/laws/shared/src/main/scala/algebra/laws/Rules.scala
index 397f6d56..8a123ea2 100644
--- a/laws/shared/src/main/scala/algebra/laws/Rules.scala
+++ b/laws/shared/src/main/scala/algebra/laws/Rules.scala
@@ -3,7 +3,6 @@ package laws
 
 import org.scalacheck.{Arbitrary, Prop}
 import org.scalacheck.Prop._
-import Prop.{False, Proof, Result}
 
 import algebra.std.boolean._
 
diff --git a/laws/shared/src/test/scala/algebra/laws/LawTests.scala b/laws/shared/src/test/scala/algebra/laws/LawTests.scala
index 0b8c231f..d3ab712f 100644
--- a/laws/shared/src/test/scala/algebra/laws/LawTests.scala
+++ b/laws/shared/src/test/scala/algebra/laws/LawTests.scala
@@ -8,11 +8,23 @@ import algebra.std.all._
 
 import org.typelevel.discipline.{Laws, Predicate}
 import org.typelevel.discipline.scalatest.Discipline
-import org.scalacheck.{Arbitrary, Gen}, Arbitrary.arbitrary
+import org.scalacheck.Arbitrary
+import Arbitrary.arbitrary
+import org.scalactic.anyvals.{PosZDouble, PosInt, PosZInt}
 import org.scalatest.FunSuite
+import org.scalatest.prop.Configuration
 import scala.util.Random
 
-trait LawTestsBase extends FunSuite with Discipline {
+trait LawTestsBase extends FunSuite with Configuration with Discipline {
+
+  lazy val checkConfiguration: PropertyCheckConfiguration =
+    PropertyCheckConfiguration(
+      minSuccessful = if (Platform.isJvm) PosInt(50) else PosInt(5),
+      maxDiscardedFactor = if (Platform.isJvm) PosZDouble(5.0) else PosZDouble(50.0),
+      minSize = PosZInt(0),
+      sizeRange = if (Platform.isJvm) PosZInt(10) else PosZInt(5),
+      workers = PosInt(1))
+
   /**
     * Runs the supplied thunk without calling the serialization tests.
     */
@@ -107,9 +119,9 @@ trait LawTestsBase extends FunSuite with Discipline {
   laws[RingLaws, Set[String]].check(_.semiring)
 
   laws[OrderLaws, Map[Char, Int]].check(_.eqv)
-  laws[RingLaws, Map[Char, Int]].check(_.rng)
+  laws[RingLaws, Map[Char, Int]].check(_.semiring)
   laws[OrderLaws, Map[Int, BigInt]].check(_.eqv)
-  laws[RingLaws, Map[Int, BigInt]].check(_.rng)
+  laws[RingLaws, Map[Int, BigInt]].check(_.semiring)
 
   laws[OrderLaws, Byte].check(_.order)
   laws[RingLaws, Byte].check(_.euclideanRing)
diff --git a/project/Boilerplate.scala b/project/Boilerplate.scala
index b3203708..718ace1f 100644
--- a/project/Boilerplate.scala
+++ b/project/Boilerplate.scala
@@ -122,23 +122,7 @@ object Boilerplate {
         |
         |import algebra.ring.{EuclideanRing, Rig, Ring, Rng, Semiring}
         |
-        |trait TupleInstances {
-        -  implicit def tuple${arity}Band[${`A..N`}](implicit ${constraints("Band")}): Band[${`(A..N)`}] =
-        -    new Band[${`(A..N)`}] {
-        -      def combine(x: ${`(A..N)`}, y: ${`(A..N)`}): ${`(A..N)`} = ${binTuple("combine")}
-        -    }
-        -
-        -  implicit def tuple${arity}Group[${`A..N`}](implicit ${constraints("Group")}): Group[${`(A..N)`}] =
-        -    new Group[${`(A..N)`}] {
-        -      def combine(x: ${`(A..N)`}, y: ${`(A..N)`}): ${`(A..N)`} = ${binTuple("combine")}
-        -      def empty: ${`(A..N)`} = ${nullaryTuple("empty")}
-        -      def inverse(x: ${`(A..N)`}): ${`(A..N)`} = ${unaryTuple("inverse")}
-        -    }
-        -
-        -  implicit def tuple${arity}Eq[${`A..N`}](implicit ${constraints("Eq")}): Eq[${`(A..N)`}] =
-        -    new Eq[${`(A..N)`}] {
-        -      def eqv(x: ${`(A..N)`}, y: ${`(A..N)`}): Boolean = ${binMethod("eqv").mkString(" && ")}
-        -    }
+        |trait TupleInstances extends cats.kernel.std.TupleInstances {
         -
         -  implicit def tuple${arity}EuclideanRing[${`A..N`}](implicit ${constraints("EuclideanRing")}): EuclideanRing[${`(A..N)`}] =
         -    new EuclideanRing[${`(A..N)`}] {
@@ -151,24 +135,6 @@ object Boilerplate {
         -      def zero: ${`(A..N)`} = ${nullaryTuple("zero")}
         -    }
         -
-        -  implicit def tuple${arity}Monoid[${`A..N`}](implicit ${constraints("Monoid")}): Monoid[${`(A..N)`}] =
-        -    new Monoid[${`(A..N)`}] {
-        -      def combine(x: ${`(A..N)`}, y: ${`(A..N)`}): ${`(A..N)`} = ${binTuple("combine")}
-        -      def empty: ${`(A..N)`} = ${nullaryTuple("empty")}
-        -    }
-        -
-        -  implicit def tuple${arity}Order[${`A..N`}](implicit ${constraints("Order")}): Order[${`(A..N)`}] =
-        -    new Order[${`(A..N)`}] {
-        -      def compare(x: ${`(A..N)`}, y: ${`(A..N)`}): Int =
-        -        ${binMethod("compare").find(_ != 0).getOrElse(0)}
-        -    }
-        -
-        -  implicit def tuple${arity}PartialOrder[${`A..N`}](implicit ${constraints("PartialOrder")}): PartialOrder[${`(A..N)`}] =
-        -    new PartialOrder[${`(A..N)`}] {
-        -      def partialCompare(x: ${`(A..N)`}, y: ${`(A..N)`}): Double =
-        -        ${binMethod("partialCompare").find(_ != 0.0).getOrElse(0.0)}
-        -    }
-        -
         -  implicit def tuple${arity}Rig[${`A..N`}](implicit ${constraints("Rig")}): Rig[${`(A..N)`}] =
         -    new Rig[${`(A..N)`}] {
         -      def one: ${`(A..N)`} = ${nullaryTuple("one")}
@@ -194,16 +160,6 @@ object Boilerplate {
         -      def negate(x: ${`(A..N)`}): ${`(A..N)`} = ${unaryTuple("negate")}
         -    }
         -
-        -  implicit def tuple${arity}Semigroup[${`A..N`}](implicit ${constraints("Semigroup")}): Semigroup[${`(A..N)`}] =
-        -    new Semigroup[${`(A..N)`}] {
-        -      def combine(x: ${`(A..N)`}, y: ${`(A..N)`}): ${`(A..N)`} = ${binTuple("combine")}
-        -    }
-        -
-        -  implicit def tuple${arity}Semilattice[${`A..N`}](implicit ${constraints("Semilattice")}): Semilattice[${`(A..N)`}] =
-        -    new Semilattice[${`(A..N)`}] {
-        -      def combine(x: ${`(A..N)`}, y: ${`(A..N)`}): ${`(A..N)`} = ${binTuple("combine")}
-        -    }
-        -
         -  implicit def tuple${arity}Semiring[${`A..N`}](implicit ${constraints("Semiring")}): Semiring[${`(A..N)`}] =
         -    new Semiring[${`(A..N)`}] {
         -      def plus(x: ${`(A..N)`}, y: ${`(A..N)`}): ${`(A..N)`} = ${binTuple("plus")}
diff --git a/project/plugins.sbt b/project/plugins.sbt
index 82630f2f..979a9de8 100644
--- a/project/plugins.sbt
+++ b/project/plugins.sbt
@@ -4,5 +4,5 @@ addSbtPlugin("com.jsuereth"      % "sbt-pgp"         % "1.0.0")
 addSbtPlugin("org.xerial.sbt"    % "sbt-sonatype"    % "0.5.0")
 addSbtPlugin("com.typesafe.sbt"  % "sbt-ghpages"     % "0.5.3")
 addSbtPlugin("com.typesafe.sbt"  % "sbt-site"        % "0.8.1")
-addSbtPlugin("org.scala-js"      % "sbt-scalajs"     % "0.6.5")
+addSbtPlugin("org.scala-js"      % "sbt-scalajs"     % "0.6.9")
 addSbtPlugin("com.typesafe"      % "sbt-mima-plugin" % "0.1.7")
diff --git a/ring/src/main/scala/algebra/ring/EuclideanRing.scala b/ring/src/main/scala/algebra/ring/EuclideanRing.scala
index 7973c7d3..90d9a07c 100644
--- a/ring/src/main/scala/algebra/ring/EuclideanRing.scala
+++ b/ring/src/main/scala/algebra/ring/EuclideanRing.scala
@@ -1,7 +1,6 @@
 package algebra
 package ring
 
-import scala.annotation.tailrec
 import scala.{specialized => sp}
 
 /**
diff --git a/ring/src/main/scala/algebra/ring/Rig.scala b/ring/src/main/scala/algebra/ring/Rig.scala
index 9fb02cdf..07cec443 100644
--- a/ring/src/main/scala/algebra/ring/Rig.scala
+++ b/ring/src/main/scala/algebra/ring/Rig.scala
@@ -1,7 +1,6 @@
 package algebra
 package ring
 
-import annotation.tailrec
 import scala.{specialized => sp}
 
 /**
diff --git a/ring/src/main/scala/algebra/ring/Rng.scala b/ring/src/main/scala/algebra/ring/Rng.scala
index 44557db4..94585327 100644
--- a/ring/src/main/scala/algebra/ring/Rng.scala
+++ b/ring/src/main/scala/algebra/ring/Rng.scala
@@ -1,7 +1,6 @@
 package algebra
 package ring
 
-import annotation.tailrec
 import scala.{specialized => sp}
 
 /**
diff --git a/ring/src/main/scala/algebra/ring/Semiring.scala b/ring/src/main/scala/algebra/ring/Semiring.scala
index 84ec3d15..e937bc6a 100644
--- a/ring/src/main/scala/algebra/ring/Semiring.scala
+++ b/ring/src/main/scala/algebra/ring/Semiring.scala
@@ -1,7 +1,6 @@
 package algebra
 package ring
 
-import annotation.tailrec
 import scala.{specialized => sp}
 
 /**
diff --git a/std/src/main/scala/algebra/std/Util.scala b/std/src/main/scala/algebra/std/Util.scala
index 43188565..e70cc4a6 100644
--- a/std/src/main/scala/algebra/std/Util.scala
+++ b/std/src/main/scala/algebra/std/Util.scala
@@ -7,6 +7,8 @@ import java.lang.Math
 import scala.annotation.tailrec
 import scala.collection.mutable
 
+import cats.kernel.std.util.StaticMethods.wrapMutableMap
+
 object StaticMethods {
 
   /**
@@ -134,46 +136,12 @@ object StaticMethods {
     }
   }
 
-  def initMutableMap[K, V](m: Map[K, V]): mutable.Map[K, V] = {
-    val result = mutable.Map.empty[K, V]
-    m.foreach { case (k, v) => result(k) = v }
-    result
-  }
-
-  def wrapMutableMap[K, V](m: mutable.Map[K, V]): Map[K, V] =
-    new WrappedMutableMap(m)
-
-  private[algebra] class WrappedMutableMap[K, V](m: mutable.Map[K, V]) extends Map[K, V] {
-    override def size: Int = m.size
-    def get(k: K): Option[V] = m.get(k)
-    def iterator: Iterator[(K, V)] = m.iterator
-    def +[V2 >: V](kv: (K, V2)): Map[K, V2] = m.toMap + kv
-    def -(key: K): Map[K, V] = m.toMap - key
-  }
-
-  def addMap[K, V](x: Map[K, V], y: Map[K, V])(f: (V, V) => V): Map[K, V] = {
-    val (small, big, g) =
-      if (x.size <= y.size) (x, y, f)
-      else (y, x, (v1: V, v2: V) => f(v2, v1))
-
-    val m = initMutableMap(big)
+  def timesMap[K, V](small: Map[K, V], big: Map[K, V])(f: (V, V) => V): Map[K, V] = {
+    val m = mutable.Map.empty[K, V]
     small.foreach { case (k, v1) =>
-      m(k) = m.get(k) match {
-        case Some(v2) => g(v1, v2)
-        case None => v1
-      }
-    }
-    wrapMutableMap(m)
-  }
-
-  def subtractMap[K, V](x: Map[K, V], y: Map[K, V])(subtract: (V, V) => V)(negate: V => V): Map[K, V] = {
-    // even if x is smaller, we'd need to call map/foreach on y to
-    // negate all its values, so this is just as fast or faster.
-    val m = initMutableMap(x)
-    y.foreach { case (k, v2) =>
-      m(k) = m.get(k) match {
-        case Some(v1) => subtract(v1, v2)
-        case None => negate(v2)
+      big.get(k) match {
+        case Some(v2) => m(k) = f(v1, v2)
+        case None => ()
       }
     }
     wrapMutableMap(m)
diff --git a/std/src/main/scala/algebra/std/all.scala b/std/src/main/scala/algebra/std/all.scala
index 4eec582b..40ebf2fc 100644
--- a/std/src/main/scala/algebra/std/all.scala
+++ b/std/src/main/scala/algebra/std/all.scala
@@ -4,7 +4,8 @@ package std
 package object all extends AllInstances
 
 trait AllInstances
-    extends BigIntInstances
+    extends ArrayInstances
+    with BigIntInstances
     with BooleanInstances
     with ByteInstances
     with CharInstances
@@ -20,4 +21,3 @@ trait AllInstances
     with StringInstances
     with TupleInstances
     with UnitInstances
-    with ArrayInstances
diff --git a/std/src/main/scala/algebra/std/array.scala b/std/src/main/scala/algebra/std/array.scala
index c25de2f0..9688ef92 100644
--- a/std/src/main/scala/algebra/std/array.scala
+++ b/std/src/main/scala/algebra/std/array.scala
@@ -1,14 +1,17 @@
 package algebra
 package std
 
-import scala.{specialized ⇒ sp}
+import scala.{ specialized ⇒ sp }
 
 package object array extends ArrayInstances
 
 trait ArrayInstances {
-  implicit def arrayEq[@sp A: Eq]: Eq[Array[A]] = new ArrayEq[A]
-  implicit def arrayOrder[@sp A: Order]: Order[Array[A]] = new ArrayOrder[A]
-  implicit def arrayPartialOrder[@sp A: PartialOrder]: PartialOrder[Array[A]] = new ArrayPartialOrder[A]
+  implicit def arrayEq[@sp A: Eq]: Eq[Array[A]] =
+    new ArrayEq[A]
+  implicit def arrayOrder[@sp A: Order]: Order[Array[A]] =
+    new ArrayOrder[A]
+  implicit def arrayPartialOrder[@sp A: PartialOrder]: PartialOrder[Array[A]] =
+    new ArrayPartialOrder[A]
 }
 
 private object ArraySupport {
@@ -18,27 +21,27 @@ private object ArraySupport {
     else if(x > 0) 1
     else 0
 
-  def eqv[@sp A: Eq](x: Array[A], y: Array[A]): Boolean = {
+  def eqv[@sp A](x: Array[A], y: Array[A])(implicit ev: Eq[A]): Boolean = {
     var i = 0
     if (x.length != y.length) return false
-    while (i < x.length && i < y.length && Eq.eqv(x(i), y(i))) i += 1
+    while (i < x.length && i < y.length && ev.eqv(x(i), y(i))) i += 1
     i == x.length
   }
 
-  def compare[@sp A: Order](x: Array[A], y: Array[A]): Int = {
+  def compare[@sp A](x: Array[A], y: Array[A])(implicit ev: Order[A]): Int = {
     var i = 0
     while (i < x.length && i < y.length) {
-      val cmp = Order.compare(x(i), y(i))
+      val cmp = ev.compare(x(i), y(i))
       if (cmp != 0) return cmp
       i += 1
     }
     signum(x.length - y.length)
   }
 
-  def partialCompare[@sp A: PartialOrder](x: Array[A], y: Array[A]): Double = {
+  def partialCompare[@sp A](x: Array[A], y: Array[A])(implicit ev: PartialOrder[A]): Double = {
     var i = 0
     while (i < x.length && i < y.length) {
-      val cmp = PartialOrder.partialCompare(x(i), y(i))
+      val cmp = ev.partialCompare(x(i), y(i))
       // Double.NaN is also != 0.0
       if (cmp != 0.0) return cmp
       i += 1
@@ -47,19 +50,23 @@ private object ArraySupport {
   }
 }
 
-private final class ArrayEq[@sp A: Eq]
-  extends Eq[Array[A]] with Serializable {
-  def eqv(x: Array[A], y: Array[A]): Boolean = ArraySupport.eqv(x, y)
+private final class ArrayEq[@sp A: Eq] extends Eq[Array[A]] with Serializable {
+  def eqv(x: Array[A], y: Array[A]): Boolean =
+    ArraySupport.eqv(x, y)
 }
 
 private final class ArrayOrder[@sp A: Order]
   extends Order[Array[A]] with Serializable {
-  override def eqv(x: Array[A], y: Array[A]): Boolean = ArraySupport.eqv(x, y)
-  def compare(x: Array[A], y: Array[A]): Int = ArraySupport.compare(x, y)
+  override def eqv(x: Array[A], y: Array[A]): Boolean =
+    ArraySupport.eqv(x, y)
+  def compare(x: Array[A], y: Array[A]): Int =
+    ArraySupport.compare(x, y)
 }
 
 private final class ArrayPartialOrder[@sp A: PartialOrder]
   extends PartialOrder[Array[A]] with Serializable {
-  override def eqv(x: Array[A], y: Array[A]): Boolean = ArraySupport.eqv(x, y)
-  override def partialCompare(x: Array[A], y: Array[A]): Double = ArraySupport.partialCompare(x, y)
+  override def eqv(x: Array[A], y: Array[A]): Boolean =
+    ArraySupport.eqv(x, y)
+  override def partialCompare(x: Array[A], y: Array[A]): Double =
+    ArraySupport.partialCompare(x, y)
 }
diff --git a/std/src/main/scala/algebra/std/bigInt.scala b/std/src/main/scala/algebra/std/bigInt.scala
index 1fcca139..3e3babf5 100644
--- a/std/src/main/scala/algebra/std/bigInt.scala
+++ b/std/src/main/scala/algebra/std/bigInt.scala
@@ -5,26 +5,16 @@ import algebra.ring._
 
 package object bigInt extends BigIntInstances
 
-trait BigIntInstances {
+trait BigIntInstances extends cats.kernel.std.BigIntInstances {
   implicit val bigIntAlgebra: BigIntAlgebra =
     new BigIntAlgebra
 }
 
-class BigIntAlgebra extends EuclideanRing[BigInt] with Order[BigInt] with Serializable {
+class BigIntAlgebra extends EuclideanRing[BigInt] with Serializable {
 
   val zero: BigInt = BigInt(0)
   val one: BigInt = BigInt(1)
 
-  def compare(x: BigInt, y: BigInt): Int = x compare y
-  override def eqv(x:BigInt, y:BigInt) = x == y
-  override def neqv(x:BigInt, y:BigInt) = x != y
-  override def gt(x: BigInt, y: BigInt) = x > y
-  override def gteqv(x: BigInt, y: BigInt) = x >= y
-  override def lt(x: BigInt, y: BigInt) = x < y
-  override def lteqv(x: BigInt, y: BigInt) = x <= y
-  override def min(x: BigInt, y: BigInt) = x min y
-  override def max(x: BigInt, y: BigInt) = x max y
-
   def plus(a: BigInt, b: BigInt): BigInt = a + b
   def negate(a: BigInt): BigInt = -a
   override def minus(a: BigInt, b: BigInt): BigInt = a - b
diff --git a/std/src/main/scala/algebra/std/boolean.scala b/std/src/main/scala/algebra/std/boolean.scala
index 5cd2c783..bb164f2d 100644
--- a/std/src/main/scala/algebra/std/boolean.scala
+++ b/std/src/main/scala/algebra/std/boolean.scala
@@ -7,7 +7,7 @@ import algebra.ring.CommutativeRig
 
 package object boolean extends BooleanInstances
 
-trait BooleanInstances {
+trait BooleanInstances extends cats.kernel.std.BooleanInstances {
   implicit val booleanAlgebra: BooleanAlgebra =
     new BooleanAlgebra
 
@@ -24,19 +24,7 @@ trait BooleanInstances {
  *
  * It uses || for plus, and && for times.
  */
-class BooleanAlgebra extends Bool[Boolean] with Order[Boolean] with CommutativeRig[Boolean] {
-  def compare(x: Boolean, y: Boolean): Int =
-    if (x == y) 0 else if (x) 1 else -1
-
-  override def eqv(x:Boolean, y:Boolean): Boolean = x == y
-  override def neqv(x:Boolean, y:Boolean): Boolean = x != y
-  override def gt(x: Boolean, y: Boolean): Boolean = x && !y
-  override def lt(x: Boolean, y: Boolean): Boolean = !x && y
-  override def gteqv(x: Boolean, y: Boolean): Boolean = x == y || x
-  override def lteqv(x: Boolean, y: Boolean): Boolean = x == y || y
-
-  override def min(x: Boolean, y: Boolean): Boolean = x && y
-  override def max(x: Boolean, y: Boolean): Boolean = x || y
+class BooleanAlgebra extends Bool[Boolean] with CommutativeRig[Boolean] {
 
   def zero: Boolean = false
   def one: Boolean = true
diff --git a/std/src/main/scala/algebra/std/byte.scala b/std/src/main/scala/algebra/std/byte.scala
index 5b7e8e18..437fef9e 100644
--- a/std/src/main/scala/algebra/std/byte.scala
+++ b/std/src/main/scala/algebra/std/byte.scala
@@ -7,25 +7,14 @@ import algebra.std.util.StaticMethods
 
 package object byte extends ByteInstances
 
-trait ByteInstances {
+trait ByteInstances extends cats.kernel.std.ByteInstances {
   implicit val byteAlgebra = new ByteAlgebra
 
   val ByteMinMaxLattice: BoundedDistributiveLattice[Byte] =
-    BoundedDistributiveLattice.minMax[Byte](Byte.MinValue, Byte.MaxValue)(byteAlgebra)
+    BoundedDistributiveLattice.minMax[Byte](Byte.MinValue, Byte.MaxValue)
 }
 
-class ByteAlgebra extends EuclideanRing[Byte]
-    with Order[Byte] with Serializable {
-
-  def compare(x: Byte, y: Byte): Int =
-    if (x < y) -1 else if (x > y) 1 else 0
-
-  override def eqv(x: Byte, y: Byte) = x == y
-  override def neqv(x: Byte, y: Byte) = x != y
-  override def gt(x: Byte, y: Byte) = x > y
-  override def gteqv(x: Byte, y: Byte) = x >= y
-  override def lt(x: Byte, y: Byte) = x < y
-  override def lteqv(x: Byte, y: Byte) = x <= y
+class ByteAlgebra extends EuclideanRing[Byte] with Serializable {
 
   def zero: Byte = 0
   def one: Byte = 1
diff --git a/std/src/main/scala/algebra/std/char.scala b/std/src/main/scala/algebra/std/char.scala
index 89f11390..7aabd536 100644
--- a/std/src/main/scala/algebra/std/char.scala
+++ b/std/src/main/scala/algebra/std/char.scala
@@ -3,17 +3,4 @@ package std
 
 package object char extends CharInstances
 
-trait CharInstances {
-  implicit val charAlgebra = new CharAlgebra
-}
-
-class CharAlgebra extends Order[Char] with Serializable {
-  def compare(x: Char, y: Char) =
-    if (x < y) -1 else if (x > y) 1 else 0
-  override def eqv(x:Char, y:Char) = x == y
-  override def neqv(x:Char, y:Char) = x != y
-  override def gt(x: Char, y: Char) = x > y
-  override def gteqv(x: Char, y: Char) = x >= y
-  override def lt(x: Char, y: Char) = x < y
-  override def lteqv(x: Char, y: Char) = x <= y
-}
+trait CharInstances extends cats.kernel.std.CharInstances
diff --git a/std/src/main/scala/algebra/std/double.scala b/std/src/main/scala/algebra/std/double.scala
index f43e4c23..f70464a9 100644
--- a/std/src/main/scala/algebra/std/double.scala
+++ b/std/src/main/scala/algebra/std/double.scala
@@ -5,18 +5,15 @@ import algebra.lattice.DistributiveLattice
 import algebra.ring.Field
 import algebra.std.util.StaticMethods
 
-import java.lang.Double.{ longBitsToDouble, doubleToLongBits }
-import java.lang.Long.{ numberOfTrailingZeros, numberOfLeadingZeros }
 import java.lang.Math
 
-import scala.annotation.tailrec
-
-trait DoubleInstances {
-  implicit val doubleAlgebra = new DoubleAlgebra
+trait DoubleInstances extends cats.kernel.std.DoubleInstances {
+  implicit val doubleAlgebra: Field[Double] =
+    new DoubleAlgebra
 
   // This is not Bounded due to the presence of NaN
   val DoubleMinMaxLattice: DistributiveLattice[Double] =
-    DistributiveLattice.minMax[Double](doubleAlgebra)
+    DistributiveLattice.minMax[Double]
 }
 
 /**
@@ -27,19 +24,7 @@ trait DoubleInstances {
  * If you would prefer an absolutely lawful fractional value, you'll
  * need to investigate rational numbers or more exotic types.
  */
-class DoubleAlgebra extends Field[Double] with Order[Double] with Serializable {
-
-  def compare(x: Double, y: Double) =
-    java.lang.Double.compare(x, y)
-
-  override def eqv(x:Double, y:Double) = x == y
-  override def neqv(x:Double, y:Double) = x != y
-  override def gt(x: Double, y: Double) = x > y
-  override def gteqv(x: Double, y: Double) = x >= y
-  override def lt(x: Double, y: Double) = x < y
-  override def lteqv(x: Double, y: Double) = x <= y
-  override def min(x: Double, y: Double) = Math.min(x, y)
-  override def max(x: Double, y: Double) = Math.max(x, y)
+class DoubleAlgebra extends Field[Double] with Serializable {
 
   def zero: Double = 0.0
   def one: Double = 1.0
diff --git a/std/src/main/scala/algebra/std/float.scala b/std/src/main/scala/algebra/std/float.scala
index 50f43f07..e89ab449 100644
--- a/std/src/main/scala/algebra/std/float.scala
+++ b/std/src/main/scala/algebra/std/float.scala
@@ -5,14 +5,14 @@ import algebra.lattice.DistributiveLattice
 import algebra.ring.Field
 import algebra.std.util.StaticMethods
 import java.lang.Math
-import scala.annotation.tailrec
 
-trait FloatInstances {
-  implicit val floatAlgebra = new FloatAlgebra
+trait FloatInstances extends cats.kernel.std.FloatInstances {
+  implicit val floatAlgebra: Field[Float] =
+    new FloatAlgebra
 
-  // Not bounded due to the presence of NaN (min(x, NaN) == NaN, max(x, NaN) == NaN)
+  // Not bounded due to the presence of NaN
   val FloatMinMaxLattice: DistributiveLattice[Float] =
-    DistributiveLattice.minMax[Float](floatAlgebra)
+    DistributiveLattice.minMax[Float]
 }
 
 /**
@@ -23,19 +23,7 @@ trait FloatInstances {
  * If you would prefer an absolutely lawful fractional value, you'll
  * need to investigate rational numbers or more exotic types.
  */
-class FloatAlgebra extends Field[Float] with Order[Float] with Serializable {
-
-  def compare(x: Float, y: Float) =
-    java.lang.Float.compare(x, y)
-
-  override def eqv(x:Float, y:Float) = x == y
-  override def neqv(x:Float, y:Float) = x != y
-  override def gt(x: Float, y: Float) = x > y
-  override def gteqv(x: Float, y: Float) = x >= y
-  override def lt(x: Float, y: Float) = x < y
-  override def lteqv(x: Float, y: Float) = x <= y
-  override def min(x: Float, y: Float) = Math.min(x, y)
-  override def max(x: Float, y: Float) = Math.max(x, y)
+class FloatAlgebra extends Field[Float] with Serializable {
 
   def zero: Float = 0.0F
   def one: Float = 1.0F
diff --git a/std/src/main/scala/algebra/std/int.scala b/std/src/main/scala/algebra/std/int.scala
index 2d318e89..00552fd5 100644
--- a/std/src/main/scala/algebra/std/int.scala
+++ b/std/src/main/scala/algebra/std/int.scala
@@ -7,25 +7,15 @@ import algebra.std.util.StaticMethods
 
 package object int extends IntInstances
 
-trait IntInstances {
-  implicit val intAlgebra = new IntAlgebra
+trait IntInstances extends cats.kernel.std.IntInstances {
+  implicit val intAlgebra: EuclideanRing[Int] =
+    new IntAlgebra
 
   val IntMinMaxLattice: BoundedDistributiveLattice[Int] =
-    BoundedDistributiveLattice.minMax[Int](Int.MinValue, Int.MaxValue)(intAlgebra)
+    BoundedDistributiveLattice.minMax[Int](Int.MinValue, Int.MaxValue)
 }
 
-class IntAlgebra extends EuclideanRing[Int]
-    with Order[Int] with Serializable {
-
-  def compare(x: Int, y: Int): Int =
-    if (x < y) -1 else if (x > y) 1 else 0
-
-  override def eqv(x: Int, y: Int) = x == y
-  override def neqv(x: Int, y: Int) = x != y
-  override def gt(x: Int, y: Int) = x > y
-  override def gteqv(x: Int, y: Int) = x >= y
-  override def lt(x: Int, y: Int) = x < y
-  override def lteqv(x: Int, y: Int) = x <= y
+class IntAlgebra extends EuclideanRing[Int] with Serializable {
 
   def zero: Int = 0
   def one: Int = 1
diff --git a/std/src/main/scala/algebra/std/list.scala b/std/src/main/scala/algebra/std/list.scala
index ec1711b3..7c386a3f 100644
--- a/std/src/main/scala/algebra/std/list.scala
+++ b/std/src/main/scala/algebra/std/list.scala
@@ -1,95 +1,6 @@
 package algebra
 package std
 
-import scala.annotation.tailrec
-import scala.collection.mutable
-
 package object list extends ListInstances 
 
-trait ListInstances extends ListInstances1 {
-  implicit def listOrder[A: Order] = new ListOrder[A]
-  implicit def listMonoid[A] = new ListMonoid[A]
-}
-
-trait ListInstances1 extends ListInstances2 {
-  implicit def listPartialOrder[A: PartialOrder] = new ListPartialOrder[A]
-}
-
-trait ListInstances2 {
-  implicit def listEq[A: Eq] = new ListEq[A]
-}
-
-class ListOrder[A](implicit ev: Order[A]) extends Order[List[A]] {
-  def compare(xs: List[A], ys: List[A]): Int = {
-    @tailrec def loop(xs: List[A], ys: List[A]): Int =
-      xs match {
-        case Nil =>
-          if (ys.isEmpty) 0 else -1
-        case x :: xs =>
-          ys match {
-            case Nil => 1
-            case y :: ys =>
-              val n = ev.compare(x, y)
-              if (n != 0) n else loop(xs, ys)
-          }
-      }
-    loop(xs, ys)
-  }
-}
-
-class ListPartialOrder[A](implicit ev: PartialOrder[A]) extends PartialOrder[List[A]] {
-  def partialCompare(xs: List[A], ys: List[A]): Double = {
-    @tailrec def loop(xs: List[A], ys: List[A]): Double =
-      xs match {
-        case Nil =>
-          if (ys.isEmpty) 0.0 else -1.0
-        case x :: xs =>
-          ys match {
-            case Nil => 1.0
-            case y :: ys =>
-              val n = ev.partialCompare(x, y)
-              if (n != 0.0) n else loop(xs, ys)
-          }
-      }
-    loop(xs, ys)
-  }
-}
-
-class ListEq[A](implicit ev: Eq[A]) extends Eq[List[A]] {
-  def eqv(x: List[A], y: List[A]): Boolean = {
-    def loop(xs: List[A], ys: List[A]): Boolean =
-      xs match {
-        case Nil =>
-          ys.isEmpty
-        case x :: xs =>
-          ys match {
-            case y :: ys =>
-              if (ev.eqv(x, y)) loop(xs, ys) else false
-            case Nil =>
-              false
-          }
-      }
-    loop(x, y)
-  }
-}
-
-class ListMonoid[A] extends Monoid[List[A]] {
-  def empty: List[A] = Nil
-  def combine(x: List[A], y: List[A]): List[A] = x ::: y
-
-  override def combineN(x: List[A], n: Int): List[A] = {
-    val buf = mutable.ListBuffer.empty[A]
-    var i = n
-    while (i > 0) {
-      buf ++= x
-      i -= 1
-    }
-    buf.toList
-  }
-
-  override def combineAll(xs: TraversableOnce[List[A]]): List[A] = {
-    val buf = mutable.ListBuffer.empty[A]
-    xs.foreach(buf ++= _)
-    buf.toList
-  }
-}
+trait ListInstances extends cats.kernel.std.ListInstances
diff --git a/std/src/main/scala/algebra/std/long.scala b/std/src/main/scala/algebra/std/long.scala
index 186b3fb9..37f6bc30 100644
--- a/std/src/main/scala/algebra/std/long.scala
+++ b/std/src/main/scala/algebra/std/long.scala
@@ -8,25 +8,15 @@ import algebra.ring._
 
 package object long extends LongInstances
 
-trait LongInstances {
-  implicit val longAlgebra = new LongAlgebra
+trait LongInstances extends cats.kernel.std.LongInstances {
+  implicit val longAlgebra: EuclideanRing[Long] =
+    new LongAlgebra
 
   val LongMinMaxLattice: BoundedDistributiveLattice[Long] =
-    BoundedDistributiveLattice.minMax[Long](Long.MinValue, Long.MaxValue)(longAlgebra)
+    BoundedDistributiveLattice.minMax[Long](Long.MinValue, Long.MaxValue)
 }
 
-class LongAlgebra extends EuclideanRing[Long]
-    with Order[Long] with Serializable {
-
-  def compare(x: Long, y: Long): Int =
-    if (x < y) -1 else if (x > y) 1 else 0
-
-  override def eqv(x: Long, y: Long) = x == y
-  override def neqv(x: Long, y: Long) = x != y
-  override def gt(x: Long, y: Long) = x > y
-  override def gteqv(x: Long, y: Long) = x >= y
-  override def lt(x: Long, y: Long) = x < y
-  override def lteqv(x: Long, y: Long) = x <= y
+class LongAlgebra extends EuclideanRing[Long] with Serializable {
 
   def zero: Long = 0
   def one: Long = 1
diff --git a/std/src/main/scala/algebra/std/map.scala b/std/src/main/scala/algebra/std/map.scala
index f362eeb2..b4ddbe05 100644
--- a/std/src/main/scala/algebra/std/map.scala
+++ b/std/src/main/scala/algebra/std/map.scala
@@ -1,17 +1,15 @@
 package algebra
 package std
 
+import cats.kernel.std.util.StaticMethods.addMap
+import algebra.std.util.StaticMethods.timesMap
 import algebra.ring._
-import algebra.std.util.StaticMethods.{addMap, initMutableMap, subtractMap, wrapMutableMap}
-import scala.collection.mutable
 
 package object map extends MapInstances
 
-trait MapInstances extends MapInstances3
+trait MapInstances extends cats.kernel.std.MapInstances with MapInstances3
 
 trait MapInstances3 extends MapInstances2 {
-  implicit def mapRng[K, V: Rng] =
-    new MapRng[K, V]
 }
 
 trait MapInstances2 extends MapInstances1 {
@@ -20,113 +18,35 @@ trait MapInstances2 extends MapInstances1 {
 }
 
 trait MapInstances1 extends MapInstances0 {
-  implicit def mapGroup[K, V: Group]: MapGroup[K, V] =
-    new MapGroup[K, V]
-  implicit def mapAdditiveGroup[K, V: AdditiveGroup]: MapAdditiveGroup[K, V] =
-    new MapAdditiveGroup[K, V]
 }
 
 trait MapInstances0 {
-  implicit def mapEq[K, V: Eq: AdditiveMonoid]: Eq[Map[K, V]] =
-    new MapVectorEq[K, V]
-  implicit def mapMonoid[K, V: Semigroup]: MapMonoid[K, V] =
-    new MapMonoid[K, V]
   implicit def mapAdditiveMonoid[K, V: AdditiveSemigroup]: MapAdditiveMonoid[K, V] =
     new MapAdditiveMonoid[K, V]
 }
 
-class MapEq[K, V](implicit V: Eq[V]) extends Eq[Map[K, V]] {
-  def eqv(x: Map[K, V], y: Map[K, V]): Boolean =
-    x.size == y.size && x.forall { case (k, v1) =>
-      y.get(k) match {
-        case Some(v2) => V.eqv(v1, v2)
-        case None => false
-      }
-    }
-}
-
-class MapVectorEq[K, V](implicit V0: Eq[V], V1: AdditiveMonoid[V]) extends Eq[Map[K, V]] {
-  private[this] def check(x: Map[K, V], y: Map[K, V]): Boolean =
-    x.forall { case (k, v1) =>
-      y.get(k) match {
-        case Some(v2) => V0.eqv(v1, v2)
-        case None => V1.isZero(v1)
-      }
-    }
-
-  def eqv(x: Map[K, V], y: Map[K, V]): Boolean =
-    (x eq y) || (check(x, y) && check(y, x))
-}
-
-class MapMonoid[K, V](implicit V: Semigroup[V]) extends Monoid[Map[K, V]]  {
-  def empty: Map[K, V] = Map.empty
-
-  def combine(x: Map[K, V], y: Map[K, V]): Map[K, V] =
-    addMap(x, y)(V.combine)
-}
-
-class MapGroup[K, V](implicit V: Group[V]) extends MapMonoid[K, V] with Group[Map[K, V]] {
-  def inverse(x: Map[K, V]): Map[K, V] =
-    x.map { case (k, v) => (k, V.inverse(v)) }
-
-  override def remove(x: Map[K, V], y: Map[K, V]): Map[K, V] =
-    subtractMap(x, y)(V.remove)(V.inverse)
-}
-
 class MapAdditiveMonoid[K, V](implicit V: AdditiveSemigroup[V]) extends AdditiveMonoid[Map[K, V]]  {
   def zero: Map[K, V] = Map.empty
 
-  def plus(x: Map[K, V], y: Map[K, V]): Map[K, V] =
-    addMap(x, y)(V.plus)
-}
-
-class MapAdditiveGroup[K, V](implicit V: AdditiveGroup[V]) extends MapAdditiveMonoid[K, V] with AdditiveGroup[Map[K, V]] {
-  def negate(x: Map[K, V]): Map[K, V] =
-    x.map { case (k, v) => (k, V.negate(v)) }
-
-  override def minus(x: Map[K, V], y: Map[K, V]): Map[K, V] =
-    subtractMap(x, y)(V.minus)(V.negate)
+  def plus(xs: Map[K, V], ys: Map[K, V]): Map[K, V] =
+    if (xs.size <= ys.size) {
+      addMap(xs, ys)((x, y) => V.plus(x, y))
+    } else {
+      addMap(ys, xs)((y, x) => V.plus(x, y))
+    }
 }
 
 class MapSemiring[K, V](implicit V: Semiring[V]) extends MapAdditiveMonoid[K, V] with Semiring[Map[K, V]] {
 
-  override def plus(x: Map[K, V], y: Map[K, V]): Map[K, V] =
-    if (y.size < x.size) plus(y, x) else {
-      val m = initMutableMap(y)
-      x.foreach { case (k, v1) =>
-        m(k) = m.get(k) match {
-          case Some(v2) => V.plus(v1, v2)
-          case None => v1
-        }
-      }
-      wrapMutableMap(m)
+  def times(xs: Map[K, V], ys: Map[K, V]): Map[K, V] =
+    if (xs.size <= ys.size) {
+      timesMap(xs, ys)((x, y) => V.times(x, y))
+    } else {
+      timesMap(ys, xs)((y, x) => V.times(x, y))
     }
 
-  def times(x: Map[K, V], y: Map[K, V]): Map[K, V] = {
-    // we can't just flip arguments to times() since
-    // V.times is not guaranteed to be commutative.
-    val (small, big, f) =
-      if (x.size <= y.size) (x, y, V.times _)
-      else (y, x, (v1: V, v2: V) => V.times(v2, v1))
-
-    val m = mutable.Map.empty[K, V]
-    small.foreach { case (k, v1) =>
-      big.get(k) match {
-        case Some(v2) => m(k) = f(v1, v2)
-        case None => ()
-      }
-    }
-    wrapMutableMap(m)
-  }
-
   override def pow(x: Map[K, V], n: Int): Map[K, V] =
-    x.map { case (k, v) => (k, V.pow(v, n)) }
-}
-
-class MapRng[K, V](implicit V: Rng[V]) extends MapSemiring[K, V] with Rng[Map[K, V]] {
-  def negate(x: Map[K, V]): Map[K, V] =
-    x.map { case (k, v) => (k, V.negate(v)) }
-
-  override def minus(x: Map[K, V], y: Map[K, V]): Map[K, V] =
-    subtractMap(x, y)(V.minus)(V.negate)
+    if (n < 1) throw new IllegalArgumentException(s"non-positive exponent: $n")
+    else if (n == 1) x
+    else x.map { case (k, v) => (k, V.pow(v, n)) }
 }
diff --git a/std/src/main/scala/algebra/std/option.scala b/std/src/main/scala/algebra/std/option.scala
index eeaf2d54..8b13c782 100644
--- a/std/src/main/scala/algebra/std/option.scala
+++ b/std/src/main/scala/algebra/std/option.scala
@@ -1,71 +1,6 @@
 package algebra
 package std
 
-import scala.annotation.tailrec
-import scala.collection.mutable
-
 package object option extends OptionInstances
 
-trait OptionInstances extends OptionInstances1 {
-  implicit def optionOrder[A: Order] = new OptionOrder[A]
-  implicit def optionMonoid[A: Semigroup] = new OptionMonoid[A]
-}
-
-trait OptionInstances1 extends OptionInstances0 {
-  implicit def optionPartialOrder[A: PartialOrder] = new OptionPartialOrder[A]
-}
-
-trait OptionInstances0 {
-  implicit def optionEq[A: Eq] = new OptionEq[A]
-}
-
-class OptionOrder[A](implicit A: Order[A]) extends Order[Option[A]] {
-  def compare(x: Option[A], y: Option[A]): Int =
-    x match {
-      case None =>
-        if (y.isEmpty) 0 else -1
-      case Some(a) =>
-        y match {
-          case None => 1
-          case Some(b) => A.compare(a, b)
-        }
-    }
-}
-
-class OptionPartialOrder[A](implicit A: PartialOrder[A]) extends PartialOrder[Option[A]] {
-  def partialCompare(x: Option[A], y: Option[A]): Double =
-    x match {
-      case None =>
-        if (y.isEmpty) 0.0 else -1.0
-      case Some(a) =>
-        y match {
-          case None => 1.0
-          case Some(b) => A.partialCompare(a, b)
-        }
-    }
-}
-
-class OptionEq[A](implicit A: Eq[A]) extends Eq[Option[A]] {
-  def eqv(x: Option[A], y: Option[A]): Boolean =
-    x match {
-      case None => y.isEmpty
-      case Some(a) =>
-        y match {
-          case None => false
-          case Some(b) => A.eqv(a, b)
-        }
-    }
-}
-
-class OptionMonoid[A](implicit A: Semigroup[A]) extends Monoid[Option[A]] {
-  def empty: Option[A] = None
-  def combine(x: Option[A], y: Option[A]): Option[A] =
-    x match {
-      case None => y
-      case Some(a) =>
-        y match {
-          case None => x
-          case Some(b) => Some(A.combine(a, b))
-        }
-    }
-}
+trait OptionInstances extends cats.kernel.std.OptionInstances
diff --git a/std/src/main/scala/algebra/std/set.scala b/std/src/main/scala/algebra/std/set.scala
index 9655c63b..4c0d6f03 100644
--- a/std/src/main/scala/algebra/std/set.scala
+++ b/std/src/main/scala/algebra/std/set.scala
@@ -6,11 +6,14 @@ import algebra.ring.{BoolRng, Semiring}
 
 package object set extends SetInstances
 
-trait SetInstances {
+trait SetInstances extends cats.kernel.std.SetInstances {
+
   implicit def setLattice[A]: GenBool[Set[A]] = new SetLattice[A]
-  implicit def setPartialOrder[A]: PartialOrder[Set[A]] = new SetPartialOrder[A]
-  implicit def setSemiring[A] = new SetSemiring[A]
-  def setBoolRng[A] = new SetBoolRng[A]
+  implicit def setSemiring[A]: Semiring[Set[A]] = new SetSemiring[A]
+
+  // this instance is not compatible with setSemiring, so it is not
+  // marked as implicit to avoid an ambiguity.
+  def setBoolRng[A]: BoolRng[Set[A]] = new SetBoolRng[A]
 }
 
 class SetLattice[A] extends GenBool[Set[A]] {
@@ -20,16 +23,6 @@ class SetLattice[A] extends GenBool[Set[A]] {
   def without(lhs: Set[A], rhs: Set[A]): Set[A] = lhs.diff(rhs)
 }
 
-class SetPartialOrder[A] extends PartialOrder[Set[A]] {
-  def partialCompare(x: Set[A], y: Set[A]): Double =
-    if (x.size < y.size) if (x.subsetOf(y)) -1.0 else Double.NaN
-    else if (y.size < x.size) -partialCompare(y, x)
-    else if (x == y) 0.0
-    else Double.NaN
-
-  override def eqv(x: Set[A], y: Set[A]): Boolean = x == y
-}
-
 class SetSemiring[A] extends Semiring[Set[A]] {
   def zero: Set[A] = Set.empty
   def plus(x: Set[A], y: Set[A]): Set[A] = x | y
diff --git a/std/src/main/scala/algebra/std/short.scala b/std/src/main/scala/algebra/std/short.scala
index 4f5d59ce..063f815a 100644
--- a/std/src/main/scala/algebra/std/short.scala
+++ b/std/src/main/scala/algebra/std/short.scala
@@ -7,25 +7,15 @@ import algebra.std.util.StaticMethods
 
 package object short extends ShortInstances
 
-trait ShortInstances {
-  implicit val shortAlgebra = new ShortAlgebra
+trait ShortInstances extends cats.kernel.std.ShortInstances {
+  implicit val shortAlgebra: EuclideanRing[Short] =
+    new ShortAlgebra
 
   val ShortMinMaxLattice: BoundedDistributiveLattice[Short] =
-    BoundedDistributiveLattice.minMax[Short](Short.MinValue, Short.MaxValue)(shortAlgebra)
+    BoundedDistributiveLattice.minMax[Short](Short.MinValue, Short.MaxValue)
 }
 
-class ShortAlgebra extends EuclideanRing[Short]
-    with Order[Short] with Serializable {
-
-  def compare(x: Short, y: Short): Int =
-    if (x < y) -1 else if (x > y) 1 else 0
-
-  override def eqv(x: Short, y: Short) = x == y
-  override def neqv(x: Short, y: Short) = x != y
-  override def gt(x: Short, y: Short) = x > y
-  override def gteqv(x: Short, y: Short) = x >= y
-  override def lt(x: Short, y: Short) = x < y
-  override def lteqv(x: Short, y: Short) = x <= y
+class ShortAlgebra extends EuclideanRing[Short] with Serializable {
 
   def zero: Short = 0
   def one: Short = 1
diff --git a/std/src/main/scala/algebra/std/string.scala b/std/src/main/scala/algebra/std/string.scala
index 522a6081..4d602fb0 100644
--- a/std/src/main/scala/algebra/std/string.scala
+++ b/std/src/main/scala/algebra/std/string.scala
@@ -3,22 +3,4 @@ package std
 
 package object string extends StringInstances
 
-trait StringInstances {
-  implicit val stringOrder: Order[String] = new StringOrder
-  implicit val stringMonoid = new StringMonoid
-}
-
-class StringOrder extends Order[String] {
-  def compare(x: String, y: String): Int = x compare y
-}
-
-class StringMonoid extends Monoid[String] {
-  def empty: String = ""
-  def combine(x: String, y: String): String = x + y
-
-  override def combineAll(xs: TraversableOnce[String]): String = {
-    val sb = new StringBuilder
-    xs.foreach(sb.append)
-    sb.toString
-  }
-}
+trait StringInstances extends cats.kernel.std.StringInstances
diff --git a/std/src/main/scala/algebra/std/unit.scala b/std/src/main/scala/algebra/std/unit.scala
index b8b83537..a77bc68e 100644
--- a/std/src/main/scala/algebra/std/unit.scala
+++ b/std/src/main/scala/algebra/std/unit.scala
@@ -5,23 +5,12 @@ import algebra.ring.CommutativeRing
 
 package object unit extends UnitInstances
 
-trait UnitInstances {
-  implicit val unitAlgebra: Order[Unit] with CommutativeRing[Unit] with BoundedSemilattice[Unit] =
+trait UnitInstances extends cats.kernel.std.UnitInstances {
+  implicit val unitRing: CommutativeRing[Unit] =
     new UnitAlgebra
 }
 
-class UnitAlgebra extends Order[Unit] with CommutativeRing[Unit] with BoundedSemilattice[Unit] {
-  def compare(x: Unit, y: Unit): Int = 0
-
-  override def eqv(x: Unit, y: Unit): Boolean = true
-  override def neqv(x: Unit, y: Unit): Boolean = false
-  override def gt(x: Unit, y: Unit): Boolean = false
-  override def lt(x: Unit, y: Unit): Boolean = false
-  override def gteqv(x: Unit, y: Unit): Boolean = true
-  override def lteqv(x: Unit, y: Unit): Boolean = true
-
-  override def min(x: Unit, y: Unit): Unit = ()
-  override def max(x: Unit, y: Unit): Unit = ()
+class UnitAlgebra extends CommutativeRing[Unit] {
 
   def zero: Unit = ()
   def one: Unit = ()
@@ -33,10 +22,4 @@ class UnitAlgebra extends Order[Unit] with CommutativeRing[Unit] with BoundedSem
   def negate(x: Unit): Unit = ()
   def times(a: Unit, b: Unit): Unit = ()
   override def pow(a: Unit, b: Int): Unit = ()
-
-  def empty: Unit = ()
-  def combine(x: Unit, y: Unit): Unit = ()
-  override protected[this] def repeatedCombineN(a: Unit, n: Int): Unit = ()
-  override def combineAllOption(as: TraversableOnce[Unit]): Option[Unit] =
-    if (as.isEmpty) None else Some(())
 }
