Skip to content

Commit b7b1f09

Browse files
authored
Remove parallel errors from ZPure (#1432)
1 parent 14e7654 commit b7b1f09

File tree

9 files changed

+44
-201
lines changed

9 files changed

+44
-201
lines changed

core-tests/shared/src/test/scala/zio/prelude/fx/ZPureSpec.scala

Lines changed: 2 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -72,9 +72,9 @@ object ZPureSpec extends ZIOBaseSpec {
7272
},
7373
test("providing environment should preserve errors") {
7474
val zPure: ZPure[Nothing, Unit, Unit, (Int, Int), Int, Int] =
75-
ZPure.fail(1).zipPar(ZPure.fail(2)).as(0)
75+
ZPure.fail(1).as(0)
7676
val actual = zPure.provideEnvironment(ZEnvironment((1, 2))).runValidation
77-
val expected = Validation.Failure(Chunk.empty, NonEmptyChunk(1, 2))
77+
val expected = Validation.Failure(Chunk.empty, NonEmptyChunk(1))
7878
assert(actual)(equalTo(expected))
7979
},
8080
test("provideSome") {
@@ -821,20 +821,6 @@ object ZPureSpec extends ZIOBaseSpec {
821821
}
822822
)
823823
),
824-
test("parallel errors example") {
825-
def validateName(s: String): ZPure[Nothing, Unit, Unit, Any, String, String] =
826-
if (s == "John Doe") ZPure.succeed(s) else ZPure.fail("Wrong name!")
827-
def validateAge(age: Int): ZPure[Nothing, Unit, Unit, Any, String, Int] =
828-
if (age >= 18) ZPure.succeed(age) else ZPure.fail("Under age")
829-
def validateAuthorized(authorized: Boolean): ZPure[Nothing, Unit, Unit, Any, String, Unit] =
830-
if (authorized) ZPure.unit else ZPure.fail("Not authorized")
831-
val validation =
832-
validateName("Jane Doe") zipPar validateAge(17) zipPar validateAuthorized(false)
833-
val result = validation.sandbox.either.run
834-
assert(result)(
835-
isLeft(equalTo(Cause("Wrong name!") && Cause("Under age") && Cause("Not authorized")))
836-
)
837-
},
838824
test("state is restored after failure") {
839825
val foo: ZPure[Nothing, String, Int, Any, Nothing, Unit] = ZPure.set(3)
840826
val bar: ZPure[Nothing, Int, String, Any, Nothing, Unit] = ZPure.set("bar")

core/shared/src/main/scala/zio/prelude/Associative.scala

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1453,15 +1453,17 @@ object Associative extends AssociativeLowPriority {
14531453

14541454
trait AssociativeLowPriority {
14551455

1456-
implicit def FxCauseProdAssociative[A]: Associative[Prod[fx.Cause[A]]] = new Associative[Prod[fx.Cause[A]]] {
1457-
def combine(l: => Prod[fx.Cause[A]], r: => Prod[fx.Cause[A]]): Prod[fx.Cause[A]] =
1458-
Prod(Prod.unwrap(l) ++ Prod.unwrap(r))
1459-
}
1456+
implicit def parSeqProdAssociative[A]: Associative[Prod[ParSeq[Unit, A]]] =
1457+
new Associative[Prod[ParSeq[Unit, A]]] {
1458+
def combine(l: => Prod[ParSeq[Unit, A]], r: => Prod[ParSeq[Unit, A]]): Prod[ParSeq[Unit, A]] =
1459+
Prod(Prod.unwrap(l) ++ Prod.unwrap(r))
1460+
}
14601461

1461-
implicit def FxCauseSumCommutative[A]: Commutative[Sum[fx.Cause[A]]] = new Commutative[Sum[fx.Cause[A]]] {
1462-
def combine(l: => Sum[fx.Cause[A]], r: => Sum[fx.Cause[A]]): Sum[fx.Cause[A]] =
1463-
Sum(Sum.unwrap(l) && Sum.unwrap(r))
1464-
}
1462+
implicit def parSeqSumCommutative[A]: Commutative[Sum[ParSeq[Unit, A]]] =
1463+
new Commutative[Sum[ParSeq[Unit, A]]] {
1464+
def combine(l: => Sum[ParSeq[Unit, A]], r: => Sum[ParSeq[Unit, A]]): Sum[ParSeq[Unit, A]] =
1465+
Sum(Sum.unwrap(l) && Sum.unwrap(r))
1466+
}
14651467

14661468
/**
14671469
* The `Commutative` and `PartialInverse` instance for the product of `Int` values.

core/shared/src/main/scala/zio/prelude/fx/ZPure.scala

Lines changed: 23 additions & 103 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,9 @@
1616

1717
package zio.prelude.fx
1818

19+
import zio._
1920
import zio.prelude._
2021
import zio.prelude.coherent.CovariantIdentityBoth
21-
import zio.{Cause => _, _}
2222

2323
import java.util.concurrent.atomic.AtomicBoolean
2424
import scala.reflect.ClassTag
@@ -36,36 +36,12 @@ import scala.util.Try
3636
sealed trait ZPure[+W, -S1, +S2, -R, +E, +A] { self =>
3737
import ZPure._
3838

39-
/**
40-
* A symbolic alias for `zipParRight`.
41-
*/
42-
final def &>[W1 >: W, S3 >: S2 <: S1, R1 <: R, E1 >: E, B, C](
43-
that: ZPure[W1, S3, S3, R1, E1, B]
44-
): ZPure[W1, S3, S3, R1, E1, B] =
45-
self zipParRight that
46-
4739
/**
4840
* A symbolic alias for `zipRight`.
4941
*/
5042
final def *>[W1 >: W, S3, R1 <: R, E1 >: E, B](that: ZPure[W1, S2, S3, R1, E1, B]): ZPure[W1, S1, S3, R1, E1, B] =
5143
self zipRight that
5244

53-
/**
54-
* A symbolic alias for `zipParLeft`.
55-
*/
56-
final def <&[W1 >: W, S3 >: S2 <: S1, R1 <: R, E1 >: E, B, C](
57-
that: ZPure[W1, S3, S3, R1, E1, B]
58-
): ZPure[W1, S3, S3, R1, E1, A] =
59-
self zipParLeft that
60-
61-
/**
62-
* A symbolic alias for `zipPar`.
63-
*/
64-
final def <&>[W1 >: W, S3 >: S2 <: S1, R1 <: R, E1 >: E, B, C](that: ZPure[W1, S3, S3, R1, E1, B])(implicit
65-
zippable: Zippable[A, B]
66-
): ZPure[W1, S3, S3, R1, E1, zippable.Out] =
67-
self zipPar that
68-
6945
/**
7046
* A symbolic alias for `zipLeft`.
7147
*/
@@ -263,12 +239,6 @@ sealed trait ZPure[+W, -S1, +S2, -R, +E, +A] { self =>
263239
): ZPure[W, S3, S3, R, Nothing, B] =
264240
self.foldM(e => ZPure.succeed(failure(e)), a => ZPure.succeed(success(a)))
265241

266-
final def foldCauseM[W1 >: W, S0 <: S1, S3, R1 <: R, E1, B](
267-
failure: Cause[E] => ZPure[W1, S0, S3, R1, E1, B],
268-
success: A => ZPure[W1, S2, S3, R1, E1, B]
269-
)(implicit ev: CanFail[E]): ZPure[W1, S0, S3, R1, E1, B] =
270-
Fold(self, failure, success)
271-
272242
/**
273243
* Recovers from errors by accepting one computation to execute for the case
274244
* of an error, and one computation to execute for the case of success.
@@ -277,7 +247,7 @@ sealed trait ZPure[+W, -S1, +S2, -R, +E, +A] { self =>
277247
failure: E => ZPure[W1, S0, S3, R1, E1, B],
278248
success: A => ZPure[W1, S2, S3, R1, E1, B]
279249
)(implicit ev: CanFail[E]): ZPure[W1, S0, S3, R1, E1, B] =
280-
foldCauseM((cause: Cause[E]) => failure(cause.first), success)
250+
Fold(self, failure, success)
281251

282252
/**
283253
* Exposes the output state into the value channel.
@@ -361,14 +331,6 @@ sealed trait ZPure[+W, -S1, +S2, -R, +E, +A] { self =>
361331
final def mapError[E1](f: E => E1)(implicit ev: CanFail[E]): ZPure[W, S1, S2, R, E1, A] =
362332
catchAll(e => fail(f(e)))
363333

364-
/**
365-
* Returns a computation with its full cause of failure mapped using the
366-
* specified function. This can be users to transform errors while
367-
* preserving the original structure of the `Cause`.
368-
*/
369-
final def mapErrorCause[E2](f: Cause[E] => Cause[E2]): ZPure[W, S1, S2, R, E2, A] =
370-
foldCauseM(cause => ZPure.failCause(f(cause)), ZPure.succeed)
371-
372334
/**
373335
* Transforms the updated state of this computation with the specified
374336
* function.
@@ -578,29 +540,29 @@ sealed trait ZPure[+W, -S1, +S2, -R, +E, +A] { self =>
578540
* the updated state and the result.
579541
*/
580542
final def run(s: S1)(implicit ev1: Any <:< R, ev2: E <:< Nothing): (S2, A) =
581-
runAll(s)._2.fold(cause => ev2(cause.first), identity)
543+
runAll(s)._2.fold(ev2, identity)
582544

583545
/**
584546
* Runs this computation with the specified initial state, returning both the
585547
* log and either all the failures that occurred or the updated state and the
586548
* result.
587549
*/
588-
final def runAll(s: S1)(implicit ev: Any <:< R): (Chunk[W], Either[Cause[E], (S2, A)]) =
550+
final def runAll(s: S1)(implicit ev: Any <:< R): (Chunk[W], Either[E, (S2, A)]) =
589551
Runner(s, self)
590552

591553
/**
592554
* Runs this computation to produce its result or the first failure to
593555
* occur.
594556
*/
595557
final def runEither(implicit ev1: Unit <:< S1, ev2: Any <:< R): Either[E, A] =
596-
runAll(())._2.fold(cause => Left(cause.first), { case (_, a) => Right(a) })
558+
runAll(())._2.fold(error => Left(error), { case (_, a) => Right(a) })
597559

598560
/**
599561
* Runs this computation to produce its result and the log.
600562
*/
601563
final def runLog(implicit ev1: Unit <:< S1, ev2: Any <:< R, ev3: E <:< Nothing): (Chunk[W], A) = {
602564
val (log, either) = runAll(())
603-
(log, either.fold(cause => ev3(cause.first), { case (_, a) => a }))
565+
(log, either.fold(error => ev3(error), { case (_, a) => a }))
604566
}
605567

606568
/**
@@ -622,16 +584,10 @@ sealed trait ZPure[+W, -S1, +S2, -R, +E, +A] { self =>
622584
*/
623585
final def runValidation(implicit ev1: Unit <:< S1, ev2: Any <:< R): ZValidation[W, E, A] =
624586
runAll(()) match {
625-
case (log, Left(cause)) => ZValidation.Failure(log, NonEmptyChunk.fromChunk(cause.toChunk).get)
587+
case (log, Left(error)) => ZValidation.Failure(log, NonEmptyChunk.single(error))
626588
case (log, Right((_, a))) => ZValidation.Success(log, a)
627589
}
628590

629-
/**
630-
* Exposes the full cause of failures of this computation.
631-
*/
632-
final def sandbox: ZPure[W, S1, S2, R, Cause[E], A] =
633-
foldCauseM(ZPure.fail, ZPure.succeed)
634-
635591
/**
636592
* Converts an option on values into an option on errors leaving the state unchanged.
637593
*/
@@ -684,7 +640,7 @@ sealed trait ZPure[+W, -S1, +S2, -R, +E, +A] { self =>
684640
def toZIO(implicit ev: Unit <:< S1): zio.ZIO[R, E, A] =
685641
ZIO.environmentWithZIO[R] { r =>
686642
provideEnvironment(r).runAll(())._2 match {
687-
case Left(cause) => ZIO.failCause(cause.toCause)
643+
case Left(error) => ZIO.fail(error)
688644
case Right((_, a)) => ZIO.succeed(a)
689645
}
690646
}
@@ -696,7 +652,7 @@ sealed trait ZPure[+W, -S1, +S2, -R, +E, +A] { self =>
696652
ZIO.environmentWithZIO[R] { r =>
697653
val result = provideEnvironment(r).runAll(s1)
698654
result._2 match {
699-
case Left(cause) => ZIO.failCause(cause.toCause)
655+
case Left(error) => ZIO.fail(error)
700656
case Right((_, a)) => ZIO.succeed(a)
701657
}
702658
}
@@ -708,7 +664,7 @@ sealed trait ZPure[+W, -S1, +S2, -R, +E, +A] { self =>
708664
ZIO.environmentWithZIO[R] { r =>
709665
val result = provideEnvironment(r).runAll(s1)
710666
result._2 match {
711-
case Left(cause) => ZIO.failCause(cause.toCause)
667+
case Left(error) => ZIO.fail(error)
712668
case Right(result) => ZIO.succeed(result)
713669
}
714670
}
@@ -720,17 +676,11 @@ sealed trait ZPure[+W, -S1, +S2, -R, +E, +A] { self =>
720676
ZIO.environmentWithZIO[R] { r =>
721677
val (log, result) = provideEnvironment(r).runAll(s1)
722678
result match {
723-
case Left(cause) => ZIO.failCause(cause.toCause)
679+
case Left(error) => ZIO.fail(error)
724680
case Right((s2, a)) => ZIO.succeed((log, s2, a))
725681
}
726682
}
727683

728-
/**
729-
* Submerges the full cause of failures of this computation.
730-
*/
731-
def unsandbox[E1](implicit ev: E <:< Cause[E1]): ZPure[W, S1, S2, R, E1, A] =
732-
foldM(e => ZPure.failCause(ev(e)), a => ZPure.succeed(a))
733-
734684
/**
735685
* Combines this computation with the specified computation, passing the
736686
* updated state from this computation to that computation and combining the
@@ -771,33 +721,6 @@ sealed trait ZPure[+W, -S1, +S2, -R, +E, +A] { self =>
771721
)(f: (A, B) => C): ZPure[W1, S1, S3, R1, E1, C] =
772722
self.flatMap(a => that.map(b => f(a, b)))
773723

774-
final def zipWithPar[W1 >: W, S3 >: S2 <: S1, R1 <: R, E1 >: E, B, C](
775-
that: ZPure[W1, S3, S3, R1, E1, B]
776-
)(f: (A, B) => C): ZPure[W1, S3, S3, R1, E1, C] =
777-
self.foldCauseM(
778-
c1 =>
779-
that.foldCauseM(
780-
c2 => ZPure.failCause(c1 && c2),
781-
_ => ZPure.failCause(c1)
782-
),
783-
a => that.map(b => f(a, b))
784-
)
785-
786-
final def zipPar[W1 >: W, S3 >: S2 <: S1, R1 <: R, E1 >: E, B, C](that: ZPure[W1, S3, S3, R1, E1, B])(implicit
787-
zippable: Zippable[A, B]
788-
): ZPure[W1, S3, S3, R1, E1, zippable.Out] =
789-
self.zipWithPar(that)(zippable.zip(_, _))
790-
791-
final def zipParLeft[W1 >: W, S3 >: S2 <: S1, R1 <: R, E1 >: E, B, C](
792-
that: ZPure[W1, S3, S3, R1, E1, B]
793-
): ZPure[W1, S3, S3, R1, E1, A] =
794-
self.zipWithPar(that)((a, _) => a)
795-
796-
final def zipParRight[W1 >: W, S3 >: S2 <: S1, R1 <: R, E1 >: E, B, C](
797-
that: ZPure[W1, S3, S3, R1, E1, B]
798-
): ZPure[W1, S3, S3, R1, E1, B] =
799-
self.zipWithPar(that)((_, b) => b)
800-
801724
/**
802725
* Returns a successful computation if the value is `Right`, or fails with error `None`.
803726
*/
@@ -915,10 +838,7 @@ object ZPure {
915838
new EnvironmentWithPurePartiallyApplied
916839

917840
def fail[E](e: E): ZPure[Nothing, Any, Nothing, Any, E, Nothing] =
918-
failCause(Cause(e))
919-
920-
def failCause[E](cause: Cause[E]): ZPure[Nothing, Any, Nothing, Any, E, Nothing] =
921-
ZPure.Fail(cause)
841+
ZPure.Fail(e)
922842

923843
/**
924844
* Constructs a computation from an `Either`.
@@ -1183,15 +1103,15 @@ object ZPure {
11831103
}
11841104

11851105
private final case class Succeed[+A](value: A) extends ZPure[Nothing, Any, Nothing, Any, Nothing, A]
1186-
private final case class Fail[+E](error: Cause[E]) extends ZPure[Nothing, Any, Nothing, Any, E, Nothing]
1106+
private final case class Fail[+E](error: E) extends ZPure[Nothing, Any, Nothing, Any, E, Nothing]
11871107
private final case class Modify[-S1, +S2, +A](run0: S1 => (A, S2)) extends ZPure[Nothing, S1, S2, Any, Nothing, A]
11881108
private final case class FlatMap[+W, -S1, S2, +S3, -R, +E, A, +B](
11891109
value: ZPure[W, S1, S2, R, E, A],
11901110
continue: A => ZPure[W, S2, S3, R, E, B]
11911111
) extends ZPure[W, S1, S3, R, E, B]
11921112
private final case class Fold[+W, -S1, S2, +S3, -R, E1, +E2, A, +B](
11931113
value: ZPure[W, S1, S2, R, E1, A],
1194-
failure: Cause[E1] => ZPure[W, S1, S3, R, E2, B],
1114+
failure: E1 => ZPure[W, S1, S3, R, E2, B],
11951115
success: A => ZPure[W, S2, S3, R, E2, B]
11961116
) extends ZPure[W, S1, S3, R, E2, B]
11971117
with Function[A, ZPure[W, S2, S3, R, E2, B]] {
@@ -1222,7 +1142,7 @@ object ZPure {
12221142
def apply[W, S1, S2, R, E, A](
12231143
state: S1,
12241144
zPure: ZPure[W, S1, S2, R, E, A]
1225-
): (Chunk[W], Either[Cause[E], (S2, A)]) = {
1145+
): (Chunk[W], Either[E, (S2, A)]) = {
12261146
val (runner, running) = pool.get()
12271147

12281148
if (running.compareAndSet(false, true)) {
@@ -1237,7 +1157,7 @@ object ZPure {
12371157
}
12381158
}
12391159

1240-
final private case class Err(cause: Cause[Any]) extends Exception {
1160+
final private case class Err(cause: Any) extends Exception {
12411161
override def fillInStackTrace(): Throwable = this
12421162
}
12431163
}
@@ -1261,12 +1181,12 @@ object ZPure {
12611181
private def run[W, S1, S2, R, E, A](
12621182
state: S1,
12631183
zPure: ZPure[W, S1, S2, R, E, A]
1264-
): (Chunk[W], Either[Cause[E], (S2, A)]) = {
1184+
): (Chunk[W], Either[E, (S2, A)]) = {
12651185
val result =
12661186
try
12671187
Right(loop(state, zPure.asInstanceOf[Erased]))
12681188
catch {
1269-
case Runner.Err(c) => Left(c.asInstanceOf[Cause[E]])
1189+
case Runner.Err(c) => Left(c.asInstanceOf[E])
12701190
}
12711191

12721192
(_logs.result().asInstanceOf[Chunk[W]], result)
@@ -1326,9 +1246,9 @@ object ZPure {
13261246

13271247
ZPure.Fold(
13281248
zPure.value,
1329-
(cause: Cause[Any]) => {
1249+
(error: Any) => {
13301250
_logs = previousLogs
1331-
ZPure.set(state) *> zPure.failure(cause)
1251+
ZPure.set(state) *> zPure.failure(error)
13321252
},
13331253
(a: Any) => {
13341254
val logs0 = _logs.result()
@@ -1340,7 +1260,7 @@ object ZPure {
13401260
} else {
13411261
ZPure.Fold(
13421262
zPure.value,
1343-
ZPure.set(state) *> zPure.failure(_: Cause[Any]),
1263+
ZPure.set(state) *> zPure.failure(_: Any),
13441264
zPure.success
13451265
)
13461266
}
@@ -1359,8 +1279,8 @@ object ZPure {
13591279
val zPure = provide0.asInstanceOf[Provide[Any, Any, Any, Any, Any, Any]]
13601280
val previousEnv = _environment
13611281
_environment = zPure.r
1362-
curZPure = zPure.continue.foldCauseM(
1363-
e => { _environment = previousEnv; ZPure.failCause(e) },
1282+
curZPure = zPure.continue.foldM(
1283+
e => { _environment = previousEnv; ZPure.fail(e) },
13641284
a => { _environment = previousEnv; ZPure.succeed(a) }
13651285
)
13661286

core/shared/src/main/scala/zio/prelude/fx/package.scala

Lines changed: 0 additions & 22 deletions
This file was deleted.

0 commit comments

Comments
 (0)