Skip to content

Commit

Permalink
Merge pull request #3263 from travisbrown/topic/de-syntax-core
Browse files Browse the repository at this point in the history
Avoid syntax methods in implementations in cats-core
  • Loading branch information
djspiewak authored Jan 29, 2020
2 parents 068aca9 + 39a721c commit bab2c3d
Show file tree
Hide file tree
Showing 15 changed files with 209 additions and 87 deletions.
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

0 comments on commit bab2c3d

Please sign in to comment.