Skip to content

Commit

Permalink
Merge pull request #1324 from non/topic/kernel-fixes
Browse files Browse the repository at this point in the history
Fix many cats-kernel instances.
  • Loading branch information
non authored Aug 24, 2016
2 parents 7feff3e + 24e4de2 commit 3ca2309
Show file tree
Hide file tree
Showing 21 changed files with 534 additions and 158 deletions.
2 changes: 1 addition & 1 deletion core/src/main/scala/cats/instances/bigDecimal.scala
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package cats
package instances

trait BigDecimalInstances {
trait BigDecimalInstances extends cats.kernel.instances.BigDecimalInstances {
implicit val catsStdShowForBigDecimal: Show[BigDecimal] =
Show.fromToString[BigDecimal]
}
78 changes: 29 additions & 49 deletions core/src/main/scala/cats/instances/either.scala
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import cats.syntax.EitherUtil
import cats.syntax.either._
import scala.annotation.tailrec

trait EitherInstances extends EitherInstances1 {
trait EitherInstances extends cats.kernel.instances.EitherInstances {
implicit val catsStdBitraverseForEither: Bitraverse[Either] =
new Bitraverse[Either] {
def bitraverse[G[_], A, B, C, D](fab: Either[A, B])(f: A => G[C], g: B => G[D])(implicit G: Applicative[G]): G[Either[C, D]] =
Expand Down Expand Up @@ -48,9 +48,13 @@ trait EitherInstances extends EitherInstances1 {
@tailrec
def tailRecM[B, C](b: B)(f: B => Either[A, Either[B, C]]): Either[A, C] =
f(b) match {
case Left(a) => Left(a)
case Right(Left(b1)) => tailRecM(b1)(f)
case Right(Right(c)) => Right(c)
case left @ Left(_) =>
left.rightCast[C]
case Right(e) =>
e match {
case Left(b1) => tailRecM(b1)(f)
case right @ Right(_) => right.leftCast[A]
}
}

override def map2Eval[B, C, Z](fb: Either[A, B], fc: Eval[Either[A, C]])(f: (B, C) => Z): Eval[Either[A, Z]] =
Expand All @@ -60,18 +64,25 @@ trait EitherInstances extends EitherInstances1 {
}

def traverse[F[_], B, C](fa: Either[A, B])(f: B => F[C])(implicit F: Applicative[F]): F[Either[A, C]] =
fa.fold(
a => F.pure(Left(a)),
b => F.map(f(b))(Right(_))
)
fa match {
case left @ Left(_) => F.pure(left.rightCast[C])
case Right(b) => F.map(f(b))(Right(_))
}

def foldLeft[B, C](fa: Either[A, B], c: C)(f: (C, B) => C): C =
fa.fold(_ => c, f(c, _))
fa match {
case Left(_) => c
case Right(b) => f(c, b)
}

def foldRight[B, C](fa: Either[A, B], lc: Eval[C])(f: (B, Eval[C]) => Eval[C]): Eval[C] =
fa.fold(_ => lc, b => f(b, lc))
fa match {
case Left(_) => lc
case Right(b) => f(b, lc)
}

override def attempt[B](fab: Either[A, B]): Either[A, Either[A, B]] = Right(fab)
override def attempt[B](fab: Either[A, B]): Either[A, Either[A, B]] =
Right(fab)
override def recover[B](fab: Either[A, B])(pf: PartialFunction[A, B]): Either[A, B] =
fab recover pf
override def recoverWith[B](fab: Either[A, B])(pf: PartialFunction[A, Either[A, B]]): Either[A, B] =
Expand All @@ -81,51 +92,20 @@ trait EitherInstances extends EitherInstances1 {
}
// scalastyle:on method.length

implicit def catsStdOrderForEither[A, B](implicit A: Order[A], B: Order[B]): Order[Either[A, B]] = new Order[Either[A, B]] {
def compare(x: Either[A, B], y: Either[A, B]): Int = x.fold(
a => y.fold(A.compare(a, _), _ => -1),
b => y.fold(_ => 1, B.compare(b, _))
)
}

implicit def catsStdShowForEither[A, B](implicit A: Show[A], B: Show[B]): Show[Either[A, B]] =
new Show[Either[A, B]] {
def show(f: Either[A, B]): String = f.fold(
a => s"Left(${A.show(a)})",
b => s"Right(${B.show(b)})"
)
}

implicit def catsDataMonoidForEither[A, B](implicit B: Monoid[B]): Monoid[Either[A, B]] =
new Monoid[Either[A, B]] {
def empty: Either[A, B] = Right(B.empty)
def combine(x: Either[A, B], y: Either[A, B]): Either[A, B] = x combine y
}

implicit def catsDataSemigroupKForEither[L]: SemigroupK[Either[L, ?]] =
new SemigroupK[Either[L, ?]] {
def combineK[A](x: Either[L, A], y: Either[L, A]): Either[L, A] = x match {
case Left(_) => y
case Right(_) => x
}
}
}

private[instances] sealed trait EitherInstances1 extends EitherInstances2 {
implicit def catsStdPartialOrderForEither[A, B](implicit A: PartialOrder[A], B: PartialOrder[B]): PartialOrder[Either[A, B]] =
new PartialOrder[Either[A, B]] {
def partialCompare(x: Either[A, B], y: Either[A, B]): Double = x.fold(
a => y.fold(A.partialCompare(a, _), _ => -1),
b => y.fold(_ => 1, B.partialCompare(b, _))
)
implicit def catsStdShowForEither[A, B](implicit A: Show[A], B: Show[B]): Show[Either[A, B]] =
new Show[Either[A, B]] {
def show(x: Either[A, B]): String =
x match {
case Left(a) => "Left(" + A.show(a) + ")"
case Right(b) => "Right(" + B.show(b) + ")"
}
}
}

private[instances] sealed trait EitherInstances2 {
implicit def catsStdEqForEither[A, B](implicit A: Eq[A], B: Eq[B]): Eq[Either[A, B]] = new Eq[Either[A, B]] {
def eqv(x: Either[A, B], y: Either[A, B]): Boolean = x.fold(
a => y.fold(A.eqv(a, _), _ => false),
b => y.fold(_ => false, B.eqv(b, _))
)
}
}
55 changes: 10 additions & 45 deletions core/src/main/scala/cats/instances/function.scala
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@ import cats.arrow.{Arrow, Choice}
import cats.functor.Contravariant
import annotation.tailrec


trait FunctionInstances extends cats.kernel.instances.FunctionInstances
with Function0Instances with Function1Instances

private[instances] sealed trait Function0Instances {

implicit val catsStdBimonadForFunction0: Bimonad[Function0] with RecursiveTailRecM[Function0] =
Expand All @@ -29,14 +33,9 @@ private[instances] sealed trait Function0Instances {
loop(a)
}
}

implicit def catsStdEqForFunction0[A](implicit A: Eq[A]): Eq[() => A] =
new Eq[() => A] {
def eqv(x: () => A, y: () => A): Boolean = A.eqv(x(), y())
}
}

private[instances] sealed trait Function1Instances extends Function1Instances0 {
private[instances] sealed trait Function1Instances {
implicit def catsStdContravariantForFunction1[R]: Contravariant[? => R] =
new Contravariant[? => R] {
def contramap[T1, T0](fa: T1 => R)(f: T0 => T1): T0 => R =
Expand Down Expand Up @@ -91,43 +90,9 @@ private[instances] sealed trait Function1Instances extends Function1Instances0 {
def compose[A, B, C](f: B => C, g: A => B): A => C = f.compose(g)
}

implicit def catsStdMonoidForFunction1[A, B](implicit M: Monoid[B]): Monoid[A => B] =
new Function1Monoid[A, B] { def B: Monoid[B] = M }

implicit val catsStdMonoidKForFunction1: MonoidK[λ[α => α => α]] =
new Function1MonoidK {}
}

private[instances] sealed trait Function1Instances0 {
implicit def catsStdSemigroupForFunction1[A, B](implicit S: Semigroup[B]): Semigroup[A => B] =
new Function1Semigroup[A, B] { def B: Semigroup[B] = S }

implicit val catsStdSemigroupKForFunction1: SemigroupK[λ[α => α => α]] =
new Function1SemigroupK {}
}

private[instances] sealed trait Function1Semigroup[A, B] extends Semigroup[A => B] {
implicit def B: Semigroup[B]

override def combine(x: A => B, y: A => B): A => B = { a =>
B.combine(x(a), y(a))
}
}

private[instances] sealed trait Function1Monoid[A, B] extends Monoid[A => B] with Function1Semigroup[A, B] {
implicit def B: Monoid[B]

override def empty: A => B = _ => B.empty
}

private[instances] sealed trait Function1SemigroupK extends SemigroupK[λ[α => α => α]] {
override def combineK[A](x: A => A, y: A => A): A => A = x compose y
}

private[instances] sealed trait Function1MonoidK extends MonoidK[λ[α => α => α]] with Function1SemigroupK {
override def empty[A]: A => A = identity[A]
implicit val catsStdMonoidKForFunction1: MonoidK[λ[α => Function1[α, α]]] =
new MonoidK[λ[α => Function1[α, α]]] {
def empty[A]: A => A = identity[A]
def combineK[A](x: A => A, y: A => A): A => A = x compose y
}
}

trait FunctionInstances
extends Function0Instances
with Function1Instances
3 changes: 2 additions & 1 deletion core/src/main/scala/cats/instances/list.scala
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ trait ListInstances extends cats.kernel.instances.ListInstances {

implicit def catsStdShowForList[A:Show]: Show[List[A]] =
new Show[List[A]] {
def show(fa: List[A]): String = fa.map(_.show).mkString("List(", ", ", ")")
def show(fa: List[A]): String =
fa.iterator.map(_.show).mkString("List(", ", ", ")")
}
}
10 changes: 5 additions & 5 deletions core/src/main/scala/cats/instances/map.scala
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,11 @@ import scala.annotation.tailrec
trait MapInstances extends cats.kernel.instances.MapInstances {

implicit def catsStdShowForMap[A, B](implicit showA: Show[A], showB: Show[B]): Show[Map[A, B]] =
Show.show[Map[A, B]] { m =>
val body = m.map { case (a, b) =>
s"${showA.show(a)} -> ${showB.show(b)})"
}.mkString(",")
s"Map($body)"
new Show[Map[A, B]] {
def show(m: Map[A, B]): String =
m.iterator
.map { case (a, b) => showA.show(a) + " -> " + showB.show(b) }
.mkString("Map(", ", ", ")")
}

// scalastyle:off method.length
Expand Down
3 changes: 2 additions & 1 deletion core/src/main/scala/cats/instances/vector.scala
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ trait VectorInstances extends cats.kernel.instances.VectorInstances {

implicit def catsStdShowForVector[A:Show]: Show[Vector[A]] =
new Show[Vector[A]] {
def show(fa: Vector[A]): String = fa.map(_.show).mkString("Vector(", ", ", ")")
def show(fa: Vector[A]): String =
fa.iterator.map(_.show).mkString("Vector(", ", ", ")")
}
}
7 changes: 4 additions & 3 deletions core/src/main/scala/cats/syntax/either.scala
Original file line number Diff line number Diff line change
Expand Up @@ -308,7 +308,8 @@ final class RightOps[A, B](val right: Right[A, B]) extends AnyVal {

/** Convenience methods to use `Either` syntax inside `Either` syntax definitions. */
private[cats] object EitherUtil {
def leftCast[A, B, C](r: Right[A, B]): Either[C, B] = new RightOps(r).leftCast[C]

def rightCast[A, B, C](l: Left[A, B]): Either[A, C] = new LeftOps(l).rightCast[C]
def leftCast[A, B, C](right: Right[A, B]): Either[C, B] =
right.asInstanceOf[Either[C, B]]
def rightCast[A, B, C](left: Left[A, B]): Either[A, C] =
left.asInstanceOf[Either[A, C]]
}
9 changes: 9 additions & 0 deletions kernel-laws/src/test/scala/cats/kernel/laws/LawTests.scala
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,9 @@ import org.typelevel.discipline.scalatest.Discipline
import org.scalacheck.{ Arbitrary, Gen }
import Arbitrary.arbitrary
import org.scalatest.FunSuite

import scala.util.Random
import scala.collection.immutable.BitSet

class LawTests extends FunSuite with Discipline {

Expand All @@ -25,6 +27,9 @@ class LawTests extends FunSuite with Discipline {
implicit def orderLaws[A: Eq: Arbitrary] = OrderLaws[A]
implicit def groupLaws[A: Eq: Arbitrary] = GroupLaws[A]

implicit val arbitraryBitSet: Arbitrary[BitSet] =
Arbitrary(arbitrary[List[Short]].map(ns => BitSet(ns.map(_ & 0xffff): _*)))

laws[OrderLaws, Map[String, HasEq[Int]]].check(_.eqv)
laws[OrderLaws, List[HasEq[Int]]].check(_.eqv)
laws[OrderLaws, Option[HasEq[Int]]].check(_.eqv)
Expand All @@ -49,6 +54,7 @@ class LawTests extends FunSuite with Discipline {
laws[OrderLaws, Char].check(_.order)
laws[OrderLaws, Int].check(_.order)
laws[OrderLaws, Long].check(_.order)
laws[OrderLaws, BitSet].check(_.partialOrder)
laws[OrderLaws, BigInt].check(_.order)
laws[OrderLaws, List[Int]].check(_.order)
laws[OrderLaws, Option[String]].check(_.order)
Expand All @@ -68,6 +74,9 @@ class LawTests extends FunSuite with Discipline {
laws[GroupLaws, List[String]].check(_.monoid)
laws[GroupLaws, Map[String, Int]].check(_.monoid)

laws[GroupLaws, BitSet].check(_.boundedSemilattice)
laws[GroupLaws, Set[Int]].check(_.boundedSemilattice)

laws[GroupLaws, Unit].check(_.commutativeGroup)
laws[GroupLaws, Byte].check(_.commutativeGroup)
laws[GroupLaws, Short].check(_.commutativeGroup)
Expand Down
11 changes: 11 additions & 0 deletions kernel/src/main/scala/cats/kernel/instances/StaticMethods.scala
Original file line number Diff line number Diff line change
Expand Up @@ -68,4 +68,15 @@ object StaticMethods {
true
}
// scalastyle:on return

def combineNIterable[A, R](b: mutable.Builder[A, R], x: Iterable[A], n: Int): R = {
var i = n
while (i > 0) { b ++= x; i -= 1 }
b.result
}

def combineAllIterable[A, R](b: mutable.Builder[A, R], xs: TraversableOnce[Iterable[A]]): R = {
xs.foreach(b ++= _)
b.result
}
}
2 changes: 2 additions & 0 deletions kernel/src/main/scala/cats/kernel/instances/all.scala
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,13 @@ package object all extends AllInstances
trait AllInstances
extends BigDecimalInstances
with BigIntInstances
with BitSetInstances
with BooleanInstances
with ByteInstances
with CharInstances
with DoubleInstances
with FloatInstances
with FunctionInstances
with IntInstances
with ListInstances
with LongInstances
Expand Down
31 changes: 31 additions & 0 deletions kernel/src/main/scala/cats/kernel/instances/bitSet.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package cats.kernel
package instances

import scala.collection.immutable.BitSet

package object bitSet extends BitSetInstances

trait BitSetInstances {
implicit val catsKernelStdPartialOrderForBitSet: PartialOrder[BitSet] =
new BitSetPartialOrder

implicit val catsKernelStdSemilatticeForBitSet: BoundedSemilattice[BitSet] =
new BitSetSemilattice
}

class BitSetPartialOrder extends PartialOrder[BitSet] {
def partialCompare(x: BitSet, y: BitSet): Double =
if (x eq y) 0.0
else if (x.size < y.size) if (x.subsetOf(y)) -1.0 else Double.NaN
else if (y.size < x.size) if (y.subsetOf(x)) 1.0 else Double.NaN
else if (x == y) 0.0
else Double.NaN

override def eqv(x: BitSet, y: BitSet): Boolean =
x == y
}

class BitSetSemilattice extends BoundedSemilattice[BitSet] {
def empty: BitSet = BitSet.empty
def combine(x: BitSet, y: BitSet): BitSet = x | y
}
2 changes: 2 additions & 0 deletions kernel/src/main/scala/cats/kernel/instances/double.scala
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ package instances

import java.lang.Math

package object double extends DoubleInstances

trait DoubleInstances {
implicit val catsKernelStdOrderForDouble: Order[Double] = new DoubleOrder
implicit val catsKernelStdGroupForDouble: CommutativeGroup[Double] = new DoubleGroup
Expand Down
Loading

0 comments on commit 3ca2309

Please sign in to comment.