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

Avoid syntax methods in implementations in cats-core #3263

Merged
merged 4 commits into from
Jan 29, 2020
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
33 changes: 33 additions & 0 deletions bench/src/main/scala/cats/bench/EitherKMapBench.scala
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package cats.bench

import cats.Functor
import cats.data.EitherK
import cats.implicits._
import org.openjdk.jmh.annotations.{Benchmark, Scope, State}

@State(Scope.Benchmark)
class EitherKMapBench {
def map1[F[_], G[_], A, B](e: EitherK[F, G, A])(f: A => B)(implicit F: Functor[F], G: Functor[G]): EitherK[F, G, B] =
EitherK(e.run.bimap(F.lift(f), G.lift(f)))

def map2[F[_], G[_], A, B](e: EitherK[F, G, A])(f: A => B)(implicit F: Functor[F], G: Functor[G]): EitherK[F, G, B] =
EitherK(
e.run match {
case Right(ga) => Right(G.map(ga)(f))
case Left(fa) => Left(F.map(fa)(f))
}
)

type EK = EitherK[List, Option, Int]

val value1 = EitherK[List, Option, Int](Right(Some(0)))
val value2 = EitherK[List, Option, Int](Right(None))
val value3 = EitherK[List, Option, Int](Left(List(1, 2)))
val f: Int => Int = _ + 1

@Benchmark
def incMap1: (EK, EK, EK) = (map1(value1)(f), map1(value2)(f), map1(value3)(f))

@Benchmark
def incMap2: (EK, EK, EK) = (map2(value1)(f), map2(value2)(f), map2(value3)(f))
}
4 changes: 1 addition & 3 deletions bench/src/main/scala/cats/bench/ValidatedBench.scala
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,12 @@ class ValidatedBench {

def bimapPointfull[E, A, EE, AA](v: Validated[E, A])(fe: E => EE, fa: A => AA): Validated[EE, AA] =
v match {
case Valid(a) => Valid(fa(a))
case Valid(a) => Valid(fa(a))
case Invalid(e) => Invalid(fe(e))
}

@Benchmark
def pointfull: Validated[Int, Int] = bimapPointfull(x)(_.length, _ + 1)


@Benchmark
def pointfree: Validated[Int, Int] = bimapPointfree(x)(_.length, _ + 1)
}
14 changes: 6 additions & 8 deletions core/src/main/scala/cats/Eval.scala
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@ package cats

import scala.annotation.tailrec

import cats.syntax.all._

/**
* Eval is a monad which controls evaluation.
*
Expand Down Expand Up @@ -416,7 +414,7 @@ sealed abstract private[cats] class EvalInstances extends EvalInstances0 {
implicit def catsOrderForEval[A: Order]: Order[Eval[A]] =
new Order[Eval[A]] {
def compare(lx: Eval[A], ly: Eval[A]): Int =
lx.value.compare(ly.value)
Order[A].compare(lx.value, ly.value)
}

implicit def catsGroupForEval[A: Group]: Group[Eval[A]] =
Expand All @@ -443,7 +441,7 @@ sealed abstract private[cats] class EvalInstances0 extends EvalInstances1 {
implicit def catsPartialOrderForEval[A: PartialOrder]: PartialOrder[Eval[A]] =
new PartialOrder[Eval[A]] {
def partialCompare(lx: Eval[A], ly: Eval[A]): Double =
lx.value.partialCompare(ly.value)
PartialOrder[A].partialCompare(lx.value, ly.value)
}

implicit def catsMonoidForEval[A: Monoid]: Monoid[Eval[A]] =
Expand All @@ -454,7 +452,7 @@ sealed abstract private[cats] class EvalInstances1 {
implicit def catsEqForEval[A: Eq]: Eq[Eval[A]] =
new Eq[Eval[A]] {
def eqv(lx: Eval[A], ly: Eval[A]): Boolean =
lx.value === ly.value
Eq[A].eqv(lx.value, ly.value)
}

implicit def catsSemigroupForEval[A: Semigroup]: Semigroup[Eval[A]] =
Expand All @@ -464,7 +462,7 @@ sealed abstract private[cats] class EvalInstances1 {
trait EvalSemigroup[A] extends Semigroup[Eval[A]] {
implicit def algebra: Semigroup[A]
def combine(lx: Eval[A], ly: Eval[A]): Eval[A] =
for { x <- lx; y <- ly } yield x |+| y
for { x <- lx; y <- ly } yield algebra.combine(x, y)
}

trait EvalMonoid[A] extends Monoid[Eval[A]] with EvalSemigroup[A] {
Expand All @@ -475,7 +473,7 @@ trait EvalMonoid[A] extends Monoid[Eval[A]] with EvalSemigroup[A] {
trait EvalGroup[A] extends Group[Eval[A]] with EvalMonoid[A] {
implicit def algebra: Group[A]
def inverse(lx: Eval[A]): Eval[A] =
lx.map(_.inverse())
lx.map(algebra.inverse)
override def remove(lx: Eval[A], ly: Eval[A]): Eval[A] =
for { x <- lx; y <- ly } yield x |-| y
for { x <- lx; y <- ly } yield algebra.remove(x, y)
}
9 changes: 6 additions & 3 deletions core/src/main/scala/cats/Reducible.scala
Original file line number Diff line number Diff line change
Expand Up @@ -257,8 +257,6 @@ import simulacrum.{noop, typeclass}
* }}}
*/
def nonEmptyPartition[A, B, C](fa: F[A])(f: A => Either[B, C]): Ior[NonEmptyList[B], NonEmptyList[C]] = {
import cats.syntax.either._

def g(a: A, eval: Eval[Ior[NonEmptyList[B], NonEmptyList[C]]]): Eval[Ior[NonEmptyList[B], NonEmptyList[C]]] =
eval.map(ior =>
(f(a), ior) match {
Expand All @@ -269,7 +267,12 @@ import simulacrum.{noop, typeclass}
}
)

reduceRightTo(fa)(a => f(a).bimap(NonEmptyList.one, NonEmptyList.one).toIor)(g).value
reduceRightTo(fa)(a =>
f(a) match {
case Right(c) => Ior.right(NonEmptyList.one(c))
case Left(b) => Ior.left(NonEmptyList.one(b))
}
)(g).value
}

override def isEmpty[A](fa: F[A]): Boolean = false
Expand Down
29 changes: 23 additions & 6 deletions core/src/main/scala/cats/data/EitherK.scala
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ package data

import cats.Contravariant
import cats.arrow.FunctionK
import cats.syntax.either._

/** `F` on the left and `G` on the right of `scala.util.Either`.
*
Expand All @@ -14,7 +13,12 @@ final case class EitherK[F[_], G[_], A](run: Either[F[A], G[A]]) {
import EitherK._

def map[B](f: A => B)(implicit F: Functor[F], G: Functor[G]): EitherK[F, G, B] =
EitherK(run.bimap(F.lift(f), G.lift(f)))
EitherK(
run match {
case Right(ga) => Right(G.map(ga)(f))
case Left(fa) => Left(F.map(fa)(f))
}
)

/**
* Modify the right side context `G` using transformation `f`.
Expand All @@ -24,17 +28,30 @@ final case class EitherK[F[_], G[_], A](run: Either[F[A], G[A]]) {

def coflatMap[B](f: EitherK[F, G, A] => B)(implicit F: CoflatMap[F], G: CoflatMap[G]): EitherK[F, G, B] =
EitherK(
run.bimap(a => F.coflatMap(a)(x => f(leftc(x))), a => G.coflatMap(a)(x => f(rightc(x))))
run match {
case Right(ga) => Right(G.coflatMap(ga)(x => f(rightc(x))))
case Left(fa) => Left(F.coflatMap(fa)(x => f(leftc(x))))
}
)

def coflatten(implicit F: CoflatMap[F], G: CoflatMap[G]): EitherK[F, G, EitherK[F, G, A]] =
EitherK(run.bimap(x => F.coflatMap(x)(a => leftc(a)), x => G.coflatMap(x)(a => rightc(a))))
EitherK(
run match {
case Right(ga) => Right(G.coflatMap(ga)(x => rightc(x)))
case Left(fa) => Left(F.coflatMap(fa)(x => leftc(x)))
}
)

def extract(implicit F: Comonad[F], G: Comonad[G]): A =
run.fold(F.extract, G.extract)

def contramap[B](f: B => A)(implicit F: Contravariant[F], G: Contravariant[G]): EitherK[F, G, B] =
EitherK(run.bimap(F.contramap(_)(f), G.contramap(_)(f)))
EitherK(
run match {
case Right(ga) => Right(G.contramap(ga)(f))
case Left(fa) => Left(F.contramap(fa)(f))
}
)

def foldRight[B](z: Eval[B])(f: (A, Eval[B]) => Eval[B])(implicit F: Foldable[F], G: Foldable[G]): Eval[B] =
run.fold(a => F.foldRight(a, z)(f), a => G.foldRight(a, z)(f))
Expand All @@ -61,7 +78,7 @@ final case class EitherK[F[_], G[_], A](run: Either[F[A], G[A]]) {
EitherK(run.swap)

def toValidated: Validated[F[A], G[A]] =
run.toValidated
Validated.fromEither(run)

/**
* Fold this eitherK into a new type constructor using two natural transformations.
Expand Down
Loading