Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix many cats-kernel instances. #1324

Merged
merged 7 commits into from
Aug 24, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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(", ", ", ")")
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nice catch

}
}
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) }
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why not s"..." here? Is + just as good? (compiled with a StringBuilder?)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thought the compiler would rewrite it to us a string builder, but maybe that's only Java? I can rewrite this using interpolation (it just ends up looking uglier IMO).

.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