From 3093d23b275002bbddf4d91def0f01cf14c3cd90 Mon Sep 17 00:00:00 2001 From: geirolz Date: Tue, 12 Mar 2024 00:04:36 +0100 Subject: [PATCH 1/2] Add recover either --- shared/src/main/scala/mouse/anyf.scala | 14 ++++- .../src/test/scala/mouse/AnyFSyntaxTest.scala | 57 ++++++++++++++++++- 2 files changed, 65 insertions(+), 6 deletions(-) diff --git a/shared/src/main/scala/mouse/anyf.scala b/shared/src/main/scala/mouse/anyf.scala index e9056bf..e4b9d4a 100644 --- a/shared/src/main/scala/mouse/anyf.scala +++ b/shared/src/main/scala/mouse/anyf.scala @@ -23,8 +23,7 @@ package mouse import cats.data.EitherT import cats.data.OptionT -import cats.~> -import cats.Functor +import cats.{Functor, MonadError, ~>} trait AnyFSyntax { implicit final def anyfSyntaxMouse[F[_], A](fa: F[A]): AnyFOps[F, A] = new AnyFOps(fa) @@ -49,4 +48,13 @@ final class AnyFOps[F[_], A](private val fa: F[A]) extends AnyVal { def liftOptionT(implicit F: Functor[F]): OptionT[F, A] = OptionT.liftF(fa) -} + // monadError error + def recoverAsLeft[E, L](pf: PartialFunction[E, L])(implicit F: MonadError[F, E]): F[Either[L, A]] = + recoverEither(pf.andThen(Left(_))) + + def recoverAsRight[E](pf: PartialFunction[E, A])(implicit F: MonadError[F, E]): F[Either[Nothing, A]] = + recoverEither(pf.andThen(Right(_))) + + def recoverEither[E, L](pf: PartialFunction[E, Either[L, A]])(implicit F: MonadError[F, E]): F[Either[L, A]] = + F.recover(mapAsRight[L])(pf) +} \ No newline at end of file diff --git a/shared/src/test/scala/mouse/AnyFSyntaxTest.scala b/shared/src/test/scala/mouse/AnyFSyntaxTest.scala index 5e87147..d8a3d25 100644 --- a/shared/src/test/scala/mouse/AnyFSyntaxTest.scala +++ b/shared/src/test/scala/mouse/AnyFSyntaxTest.scala @@ -23,9 +23,11 @@ package mouse import cats.data.EitherT import cats.data.OptionT -import cats.syntax.option._ -import cats.syntax.either._ -import cats.{~>, Id} +import cats.syntax.option.* +import cats.syntax.either.* +import cats.{Id, ~>} + +import scala.util.{Success, Try} class AnyFSyntaxTest extends MouseSuite { private val emptyK = new (List ~> List) { @@ -75,6 +77,55 @@ class AnyFSyntaxTest extends MouseSuite { assertEquals(List(1).mapAsSome, List(1.some)) } + test("AnyFSyntax.recoverEither") { + assertEquals( + Try[Int](1).recoverEither { + case _: Throwable => Right(2) + }, + Success(1.asRight) + ) + + assertEquals( + Try[Int](throw new RuntimeException("boom")).recoverEither { + case _: Throwable => Right(2) + }, + Success(2.asRight) + ) + } + + + test("AnyFSyntax.recoverAsRight") { + assertEquals( + Try[Int](1).recoverAsRight { + case _: Throwable => 2 + }, + Success(1.asRight) + ) + + assertEquals( + Try[Int](throw new RuntimeException("boom")).recoverAsRight { + case _: Throwable => 2 + }, + Success(2.asRight) + ) + } + + test("AnyFSyntax.recoverAsLeft") { + assertEquals( + Try(1).recoverAsLeft { + case _: Throwable => "foo" + }, + Success(1.asRight) + ) + + assertEquals( + Try(throw new RuntimeException("boom")).recoverAsLeft { + case _: Throwable => "error" + }, + Success("error".asLeft) + ) + } + test("AnyFSyntax.liftEitherT") { assertEquals(List(1).liftEitherT[String], EitherT(List(1.asRight[String]))) } From 3a98b5df17d5b334aa721585f2fd5ac226851c6e Mon Sep 17 00:00:00 2001 From: geirolz Date: Sat, 20 Jul 2024 09:14:43 +0200 Subject: [PATCH 2/2] Downgrade to ApplicativeError --- shared/src/main/scala/mouse/anyf.scala | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/shared/src/main/scala/mouse/anyf.scala b/shared/src/main/scala/mouse/anyf.scala index e4b9d4a..2303e6c 100644 --- a/shared/src/main/scala/mouse/anyf.scala +++ b/shared/src/main/scala/mouse/anyf.scala @@ -23,7 +23,7 @@ package mouse import cats.data.EitherT import cats.data.OptionT -import cats.{Functor, MonadError, ~>} +import cats.{ApplicativeError, Functor, MonadError, ~>} trait AnyFSyntax { implicit final def anyfSyntaxMouse[F[_], A](fa: F[A]): AnyFOps[F, A] = new AnyFOps(fa) @@ -48,13 +48,13 @@ final class AnyFOps[F[_], A](private val fa: F[A]) extends AnyVal { def liftOptionT(implicit F: Functor[F]): OptionT[F, A] = OptionT.liftF(fa) - // monadError error - def recoverAsLeft[E, L](pf: PartialFunction[E, L])(implicit F: MonadError[F, E]): F[Either[L, A]] = + // applicativeError + def recoverAsLeft[E, L](pf: PartialFunction[E, L])(implicit F: ApplicativeError[F, E]): F[Either[L, A]] = recoverEither(pf.andThen(Left(_))) - def recoverAsRight[E](pf: PartialFunction[E, A])(implicit F: MonadError[F, E]): F[Either[Nothing, A]] = + def recoverAsRight[E](pf: PartialFunction[E, A])(implicit F: ApplicativeError[F, E]): F[Either[Nothing, A]] = recoverEither(pf.andThen(Right(_))) - def recoverEither[E, L](pf: PartialFunction[E, Either[L, A]])(implicit F: MonadError[F, E]): F[Either[L, A]] = + def recoverEither[E, L](pf: PartialFunction[E, Either[L, A]])(implicit F: ApplicativeError[F, E]): F[Either[L, A]] = F.recover(mapAsRight[L])(pf) } \ No newline at end of file