Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

rename traverseX and sequenceX for Iterable #2692

Merged
merged 20 commits into from Mar 23, 2022
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
a5522cc
init
i-walker Mar 15, 2022
3872d7a
prog
i-walker Mar 15, 2022
84e9076
progress
i-walker Mar 16, 2022
7d31c3e
Update API files
i-walker Mar 16, 2022
3fb8bc1
check
i-walker Mar 16, 2022
f64dd84
Merge remote-tracking branch 'origin/is-traverse-Iterable' into is-tr…
i-walker Mar 16, 2022
2df416c
Update arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/It…
i-walker Mar 16, 2022
9b6bd9b
Update arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/It…
i-walker Mar 16, 2022
38d22d1
Update arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/It…
i-walker Mar 16, 2022
bbcbada
Update arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/It…
i-walker Mar 16, 2022
e97a6ba
Update arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/It…
i-walker Mar 16, 2022
d649b22
Update arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/It…
i-walker Mar 16, 2022
1c2e971
Update arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/It…
i-walker Mar 16, 2022
bbcfb2a
Update arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/It…
i-walker Mar 16, 2022
76fc5dc
Update arrow-libs/core/arrow-core/src/commonMain/kotlin/arrow/core/It…
i-walker Mar 16, 2022
5d47117
show that traverse Nullable and Either sequence interoperate
i-walker Mar 16, 2022
b68af90
Apply suggestions from code review
i-walker Mar 16, 2022
df90bd6
show that traverse Nullable and Either sequence interoperate
i-walker Mar 16, 2022
0469266
Merge remote-tracking branch 'origin/is-traverse-Iterable' into is-tr…
i-walker Mar 16, 2022
141b3fc
Merge branch 'main' into is-traverse-Iterable
i-walker Mar 21, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
12 changes: 12 additions & 0 deletions arrow-libs/core/arrow-core/api/arrow-core.api
Expand Up @@ -584,6 +584,12 @@ public final class arrow/core/IterableKt {
public static final fun salign (Ljava/lang/Iterable;Larrow/typeclasses/Semigroup;Ljava/lang/Iterable;)Ljava/lang/Iterable;
public static final fun separateEither (Ljava/lang/Iterable;)Lkotlin/Pair;
public static final fun separateValidated (Ljava/lang/Iterable;)Lkotlin/Pair;
public static final fun sequence (Ljava/lang/Iterable;)Larrow/core/Either;
public static final fun sequence (Ljava/lang/Iterable;)Larrow/core/Option;
public static final fun sequence (Ljava/lang/Iterable;)Larrow/core/Validated;
public static final fun sequence (Ljava/lang/Iterable;)Ljava/lang/Object;
public static final fun sequence (Ljava/lang/Iterable;)Ljava/util/List;
public static final fun sequence (Ljava/lang/Iterable;Larrow/typeclasses/Semigroup;)Larrow/core/Validated;
public static final fun sequenceEither (Ljava/lang/Iterable;)Larrow/core/Either;
public static final fun sequenceNullable (Ljava/lang/Iterable;)Ljava/util/List;
public static final fun sequenceOption (Ljava/lang/Iterable;)Larrow/core/Option;
Expand All @@ -594,6 +600,12 @@ public final class arrow/core/IterableKt {
public static final fun singleOrNone (Ljava/lang/Iterable;Lkotlin/jvm/functions/Function1;)Larrow/core/Option;
public static final fun split (Ljava/lang/Iterable;)Lkotlin/Pair;
public static final fun tail (Ljava/lang/Iterable;)Ljava/util/List;
public static final fun traverse (Ljava/lang/Iterable;Larrow/typeclasses/Semigroup;Lkotlin/jvm/functions/Function1;)Larrow/core/Validated;
public static final fun traverse (Ljava/lang/Iterable;Lkotlin/jvm/functions/Function1;)Larrow/core/Either;
public static final fun traverse (Ljava/lang/Iterable;Lkotlin/jvm/functions/Function1;)Larrow/core/Option;
public static final fun traverse (Ljava/lang/Iterable;Lkotlin/jvm/functions/Function1;)Larrow/core/Validated;
public static final fun traverse (Ljava/lang/Iterable;Lkotlin/jvm/functions/Function1;)Ljava/lang/Object;
public static final fun traverse (Ljava/lang/Iterable;Lkotlin/jvm/functions/Function1;)Ljava/util/List;
public static final fun traverseEither (Ljava/lang/Iterable;Lkotlin/jvm/functions/Function1;)Larrow/core/Either;
public static final fun traverseNullable (Ljava/lang/Iterable;Lkotlin/jvm/functions/Function1;)Ljava/util/List;
public static final fun traverseOption (Ljava/lang/Iterable;Lkotlin/jvm/functions/Function1;)Larrow/core/Option;
Expand Down
Expand Up @@ -7,6 +7,7 @@ import arrow.core.Either.Right
import arrow.typeclasses.Monoid
import arrow.typeclasses.Semigroup
import kotlin.Result.Companion.success
import kotlin.experimental.ExperimentalTypeInference

public inline fun <B, C, D, E> Iterable<B>.zip(
c: Iterable<C>,
Expand Down Expand Up @@ -282,7 +283,13 @@ public inline fun <B, C, D, E, F, G, H, I, J, K, L> Iterable<B>.zip(
internal fun <T> Iterable<T>.collectionSizeOrDefault(default: Int): Int =
if (this is Collection<*>) this.size else default

public inline fun <E, A, B> Iterable<A>.traverseEither(f: (A) -> Either<E, B>): Either<E, List<B>> {
@Deprecated("use traverse instead", ReplaceWith("traverse(f)", "arrow.core.traverse"))
i-walker marked this conversation as resolved.
Show resolved Hide resolved
public inline fun <E, A, B> Iterable<A>.traverseEither(f: (A) -> Either<E, B>): Either<E, List<B>> =
traverse(f)

@OptIn(ExperimentalTypeInference::class)
@OverloadResolutionByLambdaReturnType
public inline fun <E, A, B> Iterable<A>.traverse(f: (A) -> Either<E, B>): Either<E, List<B>> {
val destination = ArrayList<B>(collectionSizeOrDefault(10))
for (item in this) {
when (val res = f(item)) {
Expand All @@ -293,50 +300,94 @@ public inline fun <E, A, B> Iterable<A>.traverseEither(f: (A) -> Either<E, B>):
return destination.right()
}

@Deprecated("use sequence instead", ReplaceWith("sequence()", "arrow.core.sequence"))
i-walker marked this conversation as resolved.
Show resolved Hide resolved
public fun <E, A> Iterable<Either<E, A>>.sequenceEither(): Either<E, List<A>> =
traverseEither(::identity)
traverse(::identity)

public fun <E, A> Iterable<Either<E, A>>.sequence(): Either<E, List<A>> =
traverse(::identity)

public inline fun <A, B> Iterable<A>.traverseResult(f: (A) -> Result<B>): Result<List<B>> {
@OptIn(ExperimentalTypeInference::class)
@OverloadResolutionByLambdaReturnType
public inline fun <A, B> Iterable<A>.traverse(f: (A) -> Result<B>): Result<List<B>> {
val destination = ArrayList<B>(collectionSizeOrDefault(10))
for (item in this) {
f(item).fold(destination::add) { throwable ->
return@traverseResult Result.failure(throwable)
return@traverse Result.failure(throwable)
}
}
return success(destination)
}

@Deprecated("use traverse instead", ReplaceWith("traverse(f)", "arrow.core.traverse"))
i-walker marked this conversation as resolved.
Show resolved Hide resolved
public inline fun <A, B> Iterable<A>.traverseResult(f: (A) -> Result<B>): Result<List<B>> =
traverse(f)

@Deprecated("use sequence instead", ReplaceWith("sequence()", "arrow.core.sequence"))
i-walker marked this conversation as resolved.
Show resolved Hide resolved
public fun <A> Iterable<Result<A>>.sequenceResult(): Result<List<A>> =
traverseResult(::identity)
sequence()

public fun <A> Iterable<Result<A>>.sequence(): Result<List<A>> =
traverse(::identity)

@Deprecated("use traverse instead", ReplaceWith("traverse(semigroup, f)", "arrow.core.traverse"))
i-walker marked this conversation as resolved.
Show resolved Hide resolved
public inline fun <E, A, B> Iterable<A>.traverseValidated(
semigroup: Semigroup<E>,
f: (A) -> Validated<E, B>
): Validated<E, List<B>> = semigroup.run {
fold(Valid(ArrayList<B>(collectionSizeOrDefault(10))) as Validated<E, MutableList<B>>) { acc, a ->
when (val res = f(a)) {
is Validated.Valid -> when (acc) {
is Valid -> acc.also { it.value.add(res.value) }
is Invalid -> acc
}
is Validated.Invalid -> when (acc) {
is Valid -> res
is Invalid -> Invalid(acc.value.combine(res.value))
): Validated<E, List<B>> =
traverse(semigroup, f)

@OptIn(ExperimentalTypeInference::class)
@OverloadResolutionByLambdaReturnType
public inline fun <E, A, B> Iterable<A>.traverse(
semigroup: Semigroup<E>,
f: (A) -> Validated<E, B>
): Validated<E, List<B>> =
semigroup.run {
fold(Valid(ArrayList<B>(collectionSizeOrDefault(10))) as Validated<E, MutableList<B>>) { acc, a ->
when (val res = f(a)) {
is Validated.Valid -> when (acc) {
is Valid -> acc.also { it.value.add(res.value) }
is Invalid -> acc
}
is Validated.Invalid -> when (acc) {
is Valid -> res
is Invalid -> Invalid(acc.value.combine(res.value))
}
}
}
}
}

@Deprecated("use traverse instead", ReplaceWith("traverse(f)", "arrow.core.traverse"))
i-walker marked this conversation as resolved.
Show resolved Hide resolved
public inline fun <E, A, B> Iterable<A>.traverseValidated(f: (A) -> ValidatedNel<E, B>): ValidatedNel<E, List<B>> =
traverseValidated(Semigroup.nonEmptyList(), f)
traverse(f)

@OptIn(ExperimentalTypeInference::class)
@OverloadResolutionByLambdaReturnType
public inline fun <E, A, B> Iterable<A>.traverse(f: (A) -> ValidatedNel<E, B>): ValidatedNel<E, List<B>> =
traverse(Semigroup.nonEmptyList(), f)

@Deprecated("use sequence instead", ReplaceWith("sequence(semigroup)", "arrow.core.sequence"))
i-walker marked this conversation as resolved.
Show resolved Hide resolved
public fun <E, A> Iterable<Validated<E, A>>.sequenceValidated(semigroup: Semigroup<E>): Validated<E, List<A>> =
traverseValidated(semigroup, ::identity)
sequence(semigroup)

public fun <E, A> Iterable<Validated<E, A>>.sequence(semigroup: Semigroup<E>): Validated<E, List<A>> =
traverse(semigroup, ::identity)

@Deprecated("use sequence instead", ReplaceWith("sequence()", "arrow.core.sequence"))
i-walker marked this conversation as resolved.
Show resolved Hide resolved
public fun <E, A> Iterable<ValidatedNel<E, A>>.sequenceValidated(): ValidatedNel<E, List<A>> =
traverseValidated(Semigroup.nonEmptyList(), ::identity)
sequence()

public fun <E, A> Iterable<ValidatedNel<E, A>>.sequence(): ValidatedNel<E, List<A>> =
traverse(Semigroup.nonEmptyList(), ::identity)

public inline fun <A, B> Iterable<A>.traverseOption(f: (A) -> Option<B>): Option<List<B>> {
@Deprecated("use traverse instead", ReplaceWith("traverse(f)", "arrow.core.traverse"))
i-walker marked this conversation as resolved.
Show resolved Hide resolved
public inline fun <A, B> Iterable<A>.traverseOption(f: (A) -> Option<B>): Option<List<B>> =
traverse(f)

@OptIn(ExperimentalTypeInference::class)
@OverloadResolutionByLambdaReturnType
public inline fun <A, B> Iterable<A>.traverse(f: (A) -> Option<B>): Option<List<B>> {
val destination = ArrayList<B>(collectionSizeOrDefault(10))
for (item in this) {
when (val res = f(item)) {
Expand All @@ -347,10 +398,20 @@ public inline fun <A, B> Iterable<A>.traverseOption(f: (A) -> Option<B>): Option
return destination.some()
}

@Deprecated("use sequence instead", ReplaceWith("sequence()", "arrow.core.sequence"))
i-walker marked this conversation as resolved.
Show resolved Hide resolved
public fun <A> Iterable<Option<A>>.sequenceOption(): Option<List<A>> =
this.traverseOption { it }
sequence()

public fun <A> Iterable<Option<A>>.sequence(): Option<List<A>> =
traverse(::identity)

public inline fun <A, B> Iterable<A>.traverseNullable(f: (A) -> B?): List<B>? {
@Deprecated("use traverse instead", ReplaceWith("traverse(f)", "arrow.core.traverse"))
i-walker marked this conversation as resolved.
Show resolved Hide resolved
public inline fun <A, B> Iterable<A>.traverseNullable(f: (A) -> B?): List<B>? =
traverse(f)

@OptIn(ExperimentalTypeInference::class)
@OverloadResolutionByLambdaReturnType
public inline fun <A, B> Iterable<A>.traverse(f: (A) -> B?): List<B>? {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Curious that this doesn't conflict with the other traverse functions 🤔
This seems like one of those signatures that breaks all other functions 😅

What happens in the case of:

fun either(i: Int): Either<String, Int>? = null

val x: ??? = listOf(1, 2, 3).traverse { either(i) }

I guess ??? here is List<Either<String, Int>>?, and to turn it into Either<String, List<Int>>? we'd need to chain it with ?.sequence(). That'd be pretty cool if that works like that out of the box.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes this one would be List<Either<String, Int>>? I can set up a small example test

val acc = mutableListOf<B>()
forEach { a ->
val res = f(a)
Expand All @@ -363,8 +424,12 @@ public inline fun <A, B> Iterable<A>.traverseNullable(f: (A) -> B?): List<B>? {
return acc.toList()
}

@Deprecated("use sequence instead", ReplaceWith("sequence()", "arrow.core.sequence"))
i-walker marked this conversation as resolved.
Show resolved Hide resolved
public fun <A> Iterable<A?>.sequenceNullable(): List<A>? =
this.traverseNullable { it }
sequence()

public fun <A> Iterable<A?>.sequence(): List<A>? =
traverse(::identity)

public fun <A> Iterable<A>.void(): List<Unit> =
map { }
Expand Down