Skip to content

Commit

Permalink
Add zipOrAccumulate
Browse files Browse the repository at this point in the history
Closes #89, closes #90
  • Loading branch information
YuitoSato authored and michaelbull committed Nov 28, 2023
1 parent e81f581 commit 27f0a63
Show file tree
Hide file tree
Showing 2 changed files with 299 additions and 42 deletions.
272 changes: 230 additions & 42 deletions kotlin-result/src/commonMain/kotlin/com/github/michaelbull/result/Zip.kt
Original file line number Diff line number Diff line change
Expand Up @@ -12,18 +12,18 @@ private typealias Producer<T, E> = () -> Result<T, E>
* - Elm: http://package.elm-lang.org/packages/elm-lang/core/latest/Result#map2
*/
public inline fun <T1, T2, E, V> zip(
result1: Producer<T1, E>,
result2: Producer<T2, E>,
producer1: Producer<T1, E>,
producer2: Producer<T2, E>,
transform: (T1, T2) -> V
): Result<V, E> {
contract {
callsInPlace(result1, InvocationKind.EXACTLY_ONCE)
callsInPlace(result2, InvocationKind.AT_MOST_ONCE)
callsInPlace(producer1, InvocationKind.EXACTLY_ONCE)
callsInPlace(producer2, InvocationKind.AT_MOST_ONCE)
callsInPlace(transform, InvocationKind.AT_MOST_ONCE)
}

return result1().flatMap { v1 ->
result2().map { v2 ->
return producer1().flatMap { v1 ->
producer2().map { v2 ->
transform(v1, v2)
}
}
Expand All @@ -36,21 +36,21 @@ public inline fun <T1, T2, E, V> zip(
* - Elm: http://package.elm-lang.org/packages/elm-lang/core/latest/Result#map3
*/
public inline fun <T1, T2, T3, E, V> zip(
result1: Producer<T1, E>,
result2: Producer<T2, E>,
result3: Producer<T3, E>,
producer1: Producer<T1, E>,
producer2: Producer<T2, E>,
producer3: Producer<T3, E>,
transform: (T1, T2, T3) -> V
): Result<V, E> {
contract {
callsInPlace(result1, InvocationKind.EXACTLY_ONCE)
callsInPlace(result2, InvocationKind.AT_MOST_ONCE)
callsInPlace(result3, InvocationKind.AT_MOST_ONCE)
callsInPlace(producer1, InvocationKind.EXACTLY_ONCE)
callsInPlace(producer2, InvocationKind.AT_MOST_ONCE)
callsInPlace(producer3, InvocationKind.AT_MOST_ONCE)
callsInPlace(transform, InvocationKind.AT_MOST_ONCE)
}

return result1().flatMap { v1 ->
result2().flatMap { v2 ->
result3().map { v3 ->
return producer1().flatMap { v1 ->
producer2().flatMap { v2 ->
producer3().map { v3 ->
transform(v1, v2, v3)
}
}
Expand All @@ -64,24 +64,24 @@ public inline fun <T1, T2, T3, E, V> zip(
* - Elm: http://package.elm-lang.org/packages/elm-lang/core/latest/Result#map4
*/
public inline fun <T1, T2, T3, T4, E, V> zip(
result1: Producer<T1, E>,
result2: Producer<T2, E>,
result3: Producer<T3, E>,
result4: Producer<T4, E>,
producer1: Producer<T1, E>,
producer2: Producer<T2, E>,
producer3: Producer<T3, E>,
producer4: Producer<T4, E>,
transform: (T1, T2, T3, T4) -> V
): Result<V, E> {
contract {
callsInPlace(result1, InvocationKind.EXACTLY_ONCE)
callsInPlace(result2, InvocationKind.AT_MOST_ONCE)
callsInPlace(result3, InvocationKind.AT_MOST_ONCE)
callsInPlace(result4, InvocationKind.AT_MOST_ONCE)
callsInPlace(producer1, InvocationKind.EXACTLY_ONCE)
callsInPlace(producer2, InvocationKind.AT_MOST_ONCE)
callsInPlace(producer3, InvocationKind.AT_MOST_ONCE)
callsInPlace(producer4, InvocationKind.AT_MOST_ONCE)
callsInPlace(transform, InvocationKind.AT_MOST_ONCE)
}

return result1().flatMap { v1 ->
result2().flatMap { v2 ->
result3().flatMap { v3 ->
result4().map { v4 ->
return producer1().flatMap { v1 ->
producer2().flatMap { v2 ->
producer3().flatMap { v3 ->
producer4().map { v4 ->
transform(v1, v2, v3, v4)
}
}
Expand All @@ -96,31 +96,219 @@ public inline fun <T1, T2, T3, T4, E, V> zip(
* - Elm: http://package.elm-lang.org/packages/elm-lang/core/latest/Result#map5
*/
public inline fun <T1, T2, T3, T4, T5, E, V> zip(
result1: Producer<T1, E>,
result2: Producer<T2, E>,
result3: Producer<T3, E>,
result4: Producer<T4, E>,
result5: Producer<T5, E>,
producer1: Producer<T1, E>,
producer2: Producer<T2, E>,
producer3: Producer<T3, E>,
producer4: Producer<T4, E>,
producer5: Producer<T5, E>,
transform: (T1, T2, T3, T4, T5) -> V
): Result<V, E> {
contract {
callsInPlace(result1, InvocationKind.EXACTLY_ONCE)
callsInPlace(result2, InvocationKind.AT_MOST_ONCE)
callsInPlace(result3, InvocationKind.AT_MOST_ONCE)
callsInPlace(result4, InvocationKind.AT_MOST_ONCE)
callsInPlace(result5, InvocationKind.AT_MOST_ONCE)
callsInPlace(producer1, InvocationKind.EXACTLY_ONCE)
callsInPlace(producer2, InvocationKind.AT_MOST_ONCE)
callsInPlace(producer3, InvocationKind.AT_MOST_ONCE)
callsInPlace(producer4, InvocationKind.AT_MOST_ONCE)
callsInPlace(producer5, InvocationKind.AT_MOST_ONCE)
callsInPlace(transform, InvocationKind.AT_MOST_ONCE)
}

return result1().flatMap { v1 ->
result2().flatMap { v2 ->
result3().flatMap { v3 ->
result4().flatMap { v4 ->
result5().map { v5 ->
return producer1().flatMap { v1 ->
producer2().flatMap { v2 ->
producer3().flatMap { v3 ->
producer4().flatMap { v4 ->
producer5().map { v5 ->
transform(v1, v2, v3, v4, v5)
}
}
}
}
}
}

/**
* Apply a [transformation][transform] to two [Results][Result], if both [Results][Result] are [Ok].
* If not, the all arguments which are [Err] will be collected.
*/
public inline fun <T1, T2, E, V> zipOrAccumulate(
producer1: () -> Result<T1, E>,
producer2: () -> Result<T2, E>,
transform: (T1, T2) -> V,
): Result<V, List<E>> {
contract {
callsInPlace(producer1, InvocationKind.EXACTLY_ONCE)
callsInPlace(producer2, InvocationKind.EXACTLY_ONCE)
callsInPlace(transform, InvocationKind.AT_MOST_ONCE)
}

val result1 = producer1()
val result2 = producer2()

return if (
result1 is Ok &&
result2 is Ok
) {
val transformed = transform(
result1.value,
result2.value,
)

Ok(transformed)
} else {
val errors = listOf(
result1,
result2
).mapNotNull { it.getError() }

Err(errors)
}
}

/**
* Apply a [transformation][transform] to three [Results][Result], if all [Results][Result] are [Ok].
* If not, the all arguments which are [Err] will be collected.
*/
public inline fun <T1, T2, T3, E, V> zipOrAccumulate(
producer1: () -> Result<T1, E>,
producer2: () -> Result<T2, E>,
producer3: () -> Result<T3, E>,
transform: (T1, T2, T3) -> V,
): Result<V, List<E>> {
contract {
callsInPlace(producer1, InvocationKind.EXACTLY_ONCE)
callsInPlace(producer2, InvocationKind.EXACTLY_ONCE)
callsInPlace(producer3, InvocationKind.EXACTLY_ONCE)
callsInPlace(transform, InvocationKind.AT_MOST_ONCE)
}

val result1 = producer1()
val result2 = producer2()
val result3 = producer3()

return if (
result1 is Ok &&
result2 is Ok &&
result3 is Ok
) {
val transformed = transform(
result1.value,
result2.value,
result3.value
)

Ok(transformed)
} else {
val errors = listOf(
result1,
result2,
result3
).mapNotNull { it.getError() }

Err(errors)
}
}

/**
* Apply a [transformation][transform] to four [Results][Result], if all [Results][Result] are [Ok].
* If not, the all arguments which are [Err] will be collected.
*/
public inline fun <T1, T2, T3, T4, E, V> zipOrAccumulate(
producer1: () -> Result<T1, E>,
producer2: () -> Result<T2, E>,
producer3: () -> Result<T3, E>,
producer4: () -> Result<T4, E>,
transform: (T1, T2, T3, T4) -> V,
): Result<V, Collection<E>> {
contract {
callsInPlace(producer1, InvocationKind.EXACTLY_ONCE)
callsInPlace(producer2, InvocationKind.EXACTLY_ONCE)
callsInPlace(producer3, InvocationKind.EXACTLY_ONCE)
callsInPlace(producer4, InvocationKind.EXACTLY_ONCE)
callsInPlace(transform, InvocationKind.AT_MOST_ONCE)
}

val result1 = producer1()
val result2 = producer2()
val result3 = producer3()
val result4 = producer4()

return if (
result1 is Ok &&
result2 is Ok &&
result3 is Ok &&
result4 is Ok
) {
val transformed = transform(
result1.value,
result2.value,
result3.value,
result4.value
)

Ok(transformed)
} else {
val errors = listOf(
result1,
result2,
result3,
result4
).mapNotNull { it.getError() }

Err(errors)
}
}

/**
* Apply a [transformation][transform] to five [Results][Result], if all [Results][Result] are [Ok].
* If not, the all arguments which are [Err] will be collected.
*/
public inline fun <T1, T2, T3, T4, T5, E, V> zipOrAccumulate(
producer1: () -> Result<T1, E>,
producer2: () -> Result<T2, E>,
producer3: () -> Result<T3, E>,
producer4: () -> Result<T4, E>,
producer5: () -> Result<T5, E>,
transform: (T1, T2, T3, T4, T5) -> V,
): Result<V, Collection<E>> {
contract {
callsInPlace(producer1, InvocationKind.EXACTLY_ONCE)
callsInPlace(producer2, InvocationKind.EXACTLY_ONCE)
callsInPlace(producer3, InvocationKind.EXACTLY_ONCE)
callsInPlace(producer4, InvocationKind.EXACTLY_ONCE)
callsInPlace(producer5, InvocationKind.EXACTLY_ONCE)
callsInPlace(transform, InvocationKind.AT_MOST_ONCE)
}

val result1 = producer1()
val result2 = producer2()
val result3 = producer3()
val result4 = producer4()
val result5 = producer5()

return if (
result1 is Ok &&
result2 is Ok &&
result3 is Ok &&
result4 is Ok &&
result5 is Ok
) {
val transformed = transform(
result1.value,
result2.value,
result3.value,
result4.value,
result5.value
)

Ok(transformed)
} else {
val errors = listOf(
result1,
result2,
result3,
result4,
result5
).mapNotNull { it.getError() }

Err(errors)
}
}
Loading

0 comments on commit 27f0a63

Please sign in to comment.