Kotlin arrow-kt,将任一集合映射到任一集合的功能方法

Kotlin arrow-kt, functional way to map a collection of either to an either of a collection

我最近一直在使用 kotlin arrow,我 运行 遇到了一个让我卡住的特定用例。

假设我有一些对象的集合,我想使用转换函数将其转换为另一种数据类型。我们还假设这个转换函数有失败的能力——但它不会抛出异常,它只会 return 一个 Either,其中 Either.Left() 是失败而 Either.Right() 是映射目的。处理此用例的最佳方法是什么?下面是一些示例代码:

val list: Collection<Object> // some collection
val eithers: List<Either<ConvertError, NewObject>> = list.map { convert(it) } // through some logic, convert each object in the collection 

val desired: Either<ConvertError, Collection<NewObject>> = eithers.map { ??? } 


fun convert(o: Object) : Either<ConvertError, NewObject> { ... }

本质上,我想在数据集合上调用映射函数,如果任何映射响应失败,我想要一个包含错误的 Either.Left()。然后,我希望 Either.Right() 包含所有映射的对象。

有什么干净的方法可以做到这一点吗?理想情况下,我想进行一系列函数调用,但能够通过函数调用向上渗透错误。

这是一个常见的,你要找的是traverse。类似于map,只是它按照内容的聚合规则收集结果。

因此,list.k().traverse(Either.applicative()) { convert(it) } 将 return Either.Left 是任何操作 return Left,否则 Right<List<

您可以使用 Arrow 的计算块在 map 内展开 Either,如下所示:

import arrow.core.Either
import arrow.core.computations.either

val list: ListObject> // some collection
val eithers: List<Either<ConvertError, NewObject>> = list.map { convert(it) } // through some logic, convert each object in the collection 

val desired: Either<ConvertError, Collection<NewObject>> = either.eager {
  eithers.map { convert(it).bind() } 
}

fun convert(o: Object) : Either<ConvertError, NewObject> { ... }

此处 bind() 将在 EitherRight 的情况下将 Either 展开为 NewObject,否则它将退出 either.eager阻止以防它发现 LeftConvertError。这里我们使用 eager { } 变体,因为我们立即将其分配给 val。主 suspend fun either { } 块在内部支持 suspend 函数,但它本身也是一个 suspend 函数。

这是 traverse 运算符的替代方法。 traverse 操作在 Arrow 0.12.0 中将简化为以下内容:

import arrow.core.traverseEither

eithers.traverseEither(::convert) 

Arrow Fx Coroutines 中也提供了 traverse 运算符,支持并行遍历,以及该运算的一些强大的派生词。

import arrow.fx.coroutines.parTraverseEither

eithers.parTraverseEither(Dispatcheres.IO, ::convert) 

arrow.core.IterableKt#sequenceEither怎么样?

val desired: Either<ConvertError, Collection<NewObject>> = eithers.sequenceEither()