diff --git a/core/shared/src/main/scala/zio/prelude/fx/ZPure.scala b/core/shared/src/main/scala/zio/prelude/fx/ZPure.scala index c09133567..b8bb9c9e7 100644 --- a/core/shared/src/main/scala/zio/prelude/fx/ZPure.scala +++ b/core/shared/src/main/scala/zio/prelude/fx/ZPure.scala @@ -716,6 +716,15 @@ object ZPure { def modify[S1, S2, A](f: S1 => (S2, A)): ZPure[S1, S2, Any, Nothing, A] = Modify(f) + /** + * Constructs a computation that may fail from the specified modify function. + */ + def modifyEither[S1, S2, E, A](f: S1 => Either[E, (S2, A)]): ZPure[S1, S2, Any, E, A] = + get.map(f).flatMap { + case Left(e) => ZPure.fail(e) + case Right((s2, a)) => ZPure.succeed(a).asState(s2) + } + /** * Constructs a computation that extracts the second element of a tuple. */ diff --git a/core/shared/src/test/scala/zio/prelude/fx/ZPureSpec.scala b/core/shared/src/test/scala/zio/prelude/fx/ZPureSpec.scala index eaabe7d39..1ca085e27 100644 --- a/core/shared/src/test/scala/zio/prelude/fx/ZPureSpec.scala +++ b/core/shared/src/test/scala/zio/prelude/fx/ZPureSpec.scala @@ -603,7 +603,15 @@ object ZPureSpec extends DefaultRunnableSpec { assert(ZPure.fromEffect("a".toInt).runEither(()))( isLeft(equalTo(exception)) ) - } + }, + suite("modifyEither")( + test("success") { + assert(ZPure.modifyEither((_: Int) => Right((1, "success"))).run(0))(equalTo((1, "success"))) + }, + test("failure") { + assert(ZPure.modifyEither((_: Int) => Left("error")).runEither(0))(isLeft(equalTo("error"))) + } + ) ) ) )