Skip to content

Commit

Permalink
Added variation of the 'zipOrAccumulate' function
Browse files Browse the repository at this point in the history
  • Loading branch information
rcardin committed Apr 22, 2024
1 parent 4da811e commit dad234f
Show file tree
Hide file tree
Showing 3 changed files with 248 additions and 7 deletions.
72 changes: 71 additions & 1 deletion src/main/scala/in/rcard/raise4s/Fold.scala
Original file line number Diff line number Diff line change
Expand Up @@ -63,4 +63,74 @@ object RaiseIterableDef:
* A list of the transformed elements of the iterable
*/
def mapOrAccumulate(transform: Raise[Error] ?=> A => B)(using r: Raise[List[Error]]): List[B] =
Raise.mapOrAccumulate(iterable, transform)
Raise.mapOrAccumulate(iterable)(transform)

private[raise4s] def _zipOrAccumulate[Error, A, B, C, D, E, F, G, H, I, J](
action1: Raise[Error] ?=> A,
action2: Raise[Error] ?=> B,
action3: Raise[Error] ?=> C,
action4: Raise[Error] ?=> D,
action5: Raise[Error] ?=> E,
action6: Raise[Error] ?=> F,
action7: Raise[Error] ?=> G,
action8: Raise[Error] ?=> H,
action9: Raise[Error] ?=> I
)(block: (A, B, C, D, E, F, G, H, I) => J)(using r: Raise[List[Error]]): J = {
val errors = collection.mutable.ArrayBuffer.empty[Error]
val a: A = Raise.recover(
action1,
{ newError =>
errors += newError; null.asInstanceOf[A]
}
)
val b: B = Raise.recover(
action2,
{ newError =>
errors += newError; null.asInstanceOf[B]
}
)
val c: C = Raise.recover(
action3,
{ newError =>
errors += newError; null.asInstanceOf[C]
}
)
val d: D = Raise.recover(
action4,
{ newError =>
errors += newError; null.asInstanceOf[D]
}
)
val e: E = Raise.recover(
action5,
{ newError =>
errors += newError; null.asInstanceOf[E]
}
)
val f: F = Raise.recover(
action6,
{ newError =>
errors += newError; null.asInstanceOf[F]
}
)
val g: G = Raise.recover(
action7,
{ newError =>
errors += newError; null.asInstanceOf[G]
}
)
val h: H = Raise.recover(
action8,
{ newError =>
errors += newError; null.asInstanceOf[H]
}
)
val i: I = Raise.recover(
action9,
{ newError =>
errors += newError; null.asInstanceOf[I]
}
)
if errors.isEmpty then block(a, b, c, d, e, f, g, h, i)
else r.raise(errors.toList)
}
133 changes: 128 additions & 5 deletions src/main/scala/in/rcard/raise4s/Raise.scala
Original file line number Diff line number Diff line change
Expand Up @@ -390,10 +390,9 @@ object Raise {
*
* <h2>Example</h2>
* {{{
* val block: List[Int] raises List[String] = Raise.mapOrAccumulate(
* List(1, 2, 3, 4, 5),
* val block: List[Int] raises List[String] = Raise.mapOrAccumulate(List(1, 2, 3, 4, 5)) {
* _ + 1
* )
* }
* val actual = Raise.fold(
* block,
* error => fail(s"An error occurred: $error"),
Expand All @@ -417,8 +416,132 @@ object Raise {
* @return
* A list of transformed elements
*/
def mapOrAccumulate[Error, A, B](
iterable: Iterable[A],
def mapOrAccumulate[Error, A, B](iterable: Iterable[A])(
transform: Raise[Error] ?=> A => B
)(using r: Raise[List[Error]]): List[B] = _mapOrAccumulate(iterable)(transform)

def zipOrAccumulate[Error, A, B, C](
action1: Raise[Error] ?=> A,
action2: Raise[Error] ?=> B
)(block: (A, B) => C)(using r: Raise[List[Error]]): C =
Raise.zipOrAccumulate(action1, action2, {}) { (a: A, b: B, Unit) =>
block(a, b)
}

def zipOrAccumulate[Error, A, B, C, D](
action1: Raise[Error] ?=> A,
action2: Raise[Error] ?=> B,
action3: Raise[Error] ?=> C
)(
block: (A, B, C) => D
)(using r: Raise[List[Error]]): D =
Raise.zipOrAccumulate(action1, action2, action3, {}) { (a: A, b: B, c: C, Unit) =>
block(a, b, c)
}

def zipOrAccumulate[Error, A, B, C, D, E](
action1: Raise[Error] ?=> A,
action2: Raise[Error] ?=> B,
action3: Raise[Error] ?=> C,
action4: Raise[Error] ?=> D
)(
block: (A, B, C, D) => E
)(using r: Raise[List[Error]]): E =
Raise.zipOrAccumulate(action1, action2, action3, action4, {}) {
(a: A, b: B, c: C, d: D, Unit) =>
block(a, b, c, d)
}

def zipOrAccumulate[Error, A, B, C, D, E, F](
action1: Raise[Error] ?=> A,
action2: Raise[Error] ?=> B,
action3: Raise[Error] ?=> C,
action4: Raise[Error] ?=> D,
action5: Raise[Error] ?=> E
)(
block: (A, B, C, D, E) => F
)(using r: Raise[List[Error]]): F =
Raise.zipOrAccumulate(action1, action2, action3, action4, action5, {}) {
(a: A, b: B, c: C, d: D, e: E, Unit) => block(a, b, c, d, e)
}

def zipOrAccumulate[Error, A, B, C, D, E, F, G](
action1: Raise[Error] ?=> A,
action2: Raise[Error] ?=> B,
action3: Raise[Error] ?=> C,
action4: Raise[Error] ?=> D,
action5: Raise[Error] ?=> E,
action6: Raise[Error] ?=> F
)(
block: (A, B, C, D, E, F) => G
)(using r: Raise[List[Error]]): G =
Raise.zipOrAccumulate(action1, action2, action3, action4, action5, action6, {}) {
(a: A, b: B, c: C, d: D, e: E, f: F, Unit) => block(a, b, c, d, e, f)
}

def zipOrAccumulate[Error, A, B, C, D, E, F, G, H](
action1: Raise[Error] ?=> A,
action2: Raise[Error] ?=> B,
action3: Raise[Error] ?=> C,
action4: Raise[Error] ?=> D,
action5: Raise[Error] ?=> E,
action6: Raise[Error] ?=> F,
action7: Raise[Error] ?=> G
)(
block: (A, B, C, D, E, F, G) => H
)(using r: Raise[List[Error]]): H =
Raise.zipOrAccumulate(action1, action2, action3, action4, action5, action6, action7, {}) {
(a: A, b: B, c: C, d: D, e: E, f: F, g: G, Unit) => block(a, b, c, d, e, f, g)
}

def zipOrAccumulate[Error, A, B, C, D, E, F, G, H, I](
action1: Raise[Error] ?=> A,
action2: Raise[Error] ?=> B,
action3: Raise[Error] ?=> C,
action4: Raise[Error] ?=> D,
action5: Raise[Error] ?=> E,
action6: Raise[Error] ?=> F,
action7: Raise[Error] ?=> G,
action8: Raise[Error] ?=> H
)(
block: (A, B, C, D, E, F, G, H) => I
)(using r: Raise[List[Error]]): I =
Raise.zipOrAccumulate(
action1,
action2,
action3,
action4,
action5,
action6,
action7,
action8,
{}
) { (a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, Unit) =>
block(a, b, c, d, e, f, g, h)
}

def zipOrAccumulate[Error, A, B, C, D, E, F, G, H, I, J](
action1: Raise[Error] ?=> A,
action2: Raise[Error] ?=> B,
action3: Raise[Error] ?=> C,
action4: Raise[Error] ?=> D,
action5: Raise[Error] ?=> E,
action6: Raise[Error] ?=> F,
action7: Raise[Error] ?=> G,
action8: Raise[Error] ?=> H,
action9: Raise[Error] ?=> I
)(block: (A, B, C, D, E, F, G, H, I) => J)(using r: Raise[List[Error]]): J =
_zipOrAccumulate(
action1,
action2,
action3,
action4,
action5,
action6,
action7,
action8,
action9
)(
block
)
}
50 changes: 49 additions & 1 deletion src/test/scala/in/rcard/raise4s/FoldSpec.scala
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ class FoldSpec extends AnyFlatSpec with Matchers {

"mapOrAccumulate" should "map all the element of the iterable" in {
val block: List[Int] raises List[String] = Raise.mapOrAccumulate(List(1, 2, 3, 4, 5)) {
_ + 1
value1 => value1 + 1
}

val actual = Raise.fold(
Expand Down Expand Up @@ -144,4 +144,52 @@ class FoldSpec extends AnyFlatSpec with Matchers {

actual shouldBe List("2", "4")
}

"zipOrAccumulate" should "zip 9 elements" in {
val block: List[Int] raises List[String] = Raise.zipOrAccumulate(
{ 1 },
{ 2 },
{ 3 },
{ 4 },
{ 5 },
{ 6 },
{ 7 },
{ 8 },
{ 9 }
) { case (a, b, c, d, e, f, g, h, i) =>
List(a, b, c, d, e, f, g, h, i)
}

val actual = Raise.fold(
block,
error => fail(s"An error occurred: $error"),
identity
)

actual should be(List(1, 2, 3, 4, 5, 6, 7, 8, 9))
}

it should "accumulate errors" in {
val block: List[Int] raises List[String] = Raise.zipOrAccumulate(
{ 1 },
{ if (true) Raise.raise("2") else 2 },
{ 3 },
{ if (true) Raise.raise("4") else 4 },
{ 5 },
{ if (true) Raise.raise("6") else 6 },
{ 7 },
{ if (true) Raise.raise("8") else 8 },
{ 9 }
) { case (a, b, c, d, e, f, g, h, i) =>
List(a, b, c, d, e, f, g, h, i)
}

val actual = Raise.fold(
block,
identity,
identity
)

actual should be(List("2", "4", "6", "8"))
}
}

0 comments on commit dad234f

Please sign in to comment.