4

我最近一直在使用 kotlin arrow,但我遇到了一个让我陷入困境的特定用例。

假设我有一些对象的集合,我想使用转换函数将其转换为另一种数据类型。还可以说这个转换函数有失败的能力——但不是抛出异常,它只会返回一个 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()包含所有映射的对象。

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

4

3 回答 3

3

这是一个常见的,你正在寻找的是所谓的traverse。就像map,只是它按照内容的聚合规则收集结果。

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

于 2021-02-26T22:07:22.503 回答
3

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

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()要么Either在isNewObject的情况下展开,要么在它找到with的情况下退出块。在这里,我们使用变体,因为我们将其立即分配给 a。主块支持内部功能,但它本身也是一个功能。EitherRighteither.eagerLeftConvertErroreager { }valsuspend fun either { }suspendsuspend

这是traverse运营商的替代品。该traverse操作将在 Arrow 0.12.0 中简化为以下内容:

import arrow.core.traverseEither

eithers.traverseEither(::convert) 

traverse运算符在 Arrow Fx Coroutines 中也可用,支持并行遍历,以及此操作的一些强大派生。

import arrow.fx.coroutines.parTraverseEither

eithers.parTraverseEither(Dispatcheres.IO, ::convert) 
于 2021-02-27T14:05:34.313 回答
0

怎么样arrow.core.IterableKt#sequenceEither

val desired: Either<ConvertError, Collection<NewObject>> = eithers.sequenceEither()
于 2022-02-08T10:38:40.597 回答