diff --git a/std/src/main/scala/cats/std/all.scala b/std/src/main/scala/cats/std/all.scala index 8c435a6443..bac11a54e5 100644 --- a/std/src/main/scala/cats/std/all.scala +++ b/std/src/main/scala/cats/std/all.scala @@ -2,6 +2,7 @@ package cats.std trait AllInstances extends FunctionInstances + with EitherInstances with ListInstances with OptionInstances with SetInstances diff --git a/std/src/main/scala/cats/std/either.scala b/std/src/main/scala/cats/std/either.scala new file mode 100644 index 0000000000..3280390c78 --- /dev/null +++ b/std/src/main/scala/cats/std/either.scala @@ -0,0 +1,64 @@ +package cats +package std + +trait EitherInstances extends EitherInstances1 { + implicit def eitherInstances[A]: Monad[Either[A, ?]] with Traverse[Either[A, ?]] = + new Monad[Either[A, ?]] with Traverse[Either[A, ?]] { + def pure[B](b: B): Either[A, B] = Right(b) + + def flatMap[B, C](fa: Either[A, B])(f: B => Either[A, C]): Either[A, C] = + fa.right.flatMap(f) + + override def map[B, C](fa: Either[A, B])(f: B => C): Either[A, C] = + fa.right.map(f) + + 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(_)) + ) + + def foldLeft[B, C](fa: Either[A, B], c: C)(f: (C, B) => C): C = + fa.fold(_ => c, f(c, _)) + + def foldRight[B, C](fa: Either[A, B], c: C)(f: (B, C) => C): C = + fa.fold(_ => c, f(_, c)) + + def foldRight[B, C](fa: Either[A, B], c: Lazy[C])(f: (B, Lazy[C]) => C): Lazy[C] = + fa.fold(_ => c, b => Lazy(f(b, c))) + } + + implicit def eitherOrder[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 eitherShow[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)})" + ) + } +} + +sealed trait EitherInstances1 extends EitherInstances2 { + implicit def eitherPartialOrder[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, _)) + ) + } +} + +sealed trait EitherInstances2 { + implicit def eitherEq[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, _)) + ) + } +} diff --git a/std/src/main/scala/cats/std/package.scala b/std/src/main/scala/cats/std/package.scala index 88fe488184..9e85fa6841 100644 --- a/std/src/main/scala/cats/std/package.scala +++ b/std/src/main/scala/cats/std/package.scala @@ -3,6 +3,7 @@ package cats package object std { object all extends AllInstances + object either extends EitherInstances object function extends FunctionInstances object list extends ListInstances object option extends OptionInstances