【问题标题】:Kotlin arrow-kt, functional way to map a collection of either to an either of a collectionKotlin arrow-kt,将任一集合映射到任一集合的功能性方式
【发布时间】:2021-02-26 20:54:56
【问题描述】:

我最近一直在使用 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() 包含所有映射对象。

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

【问题讨论】:

    标签: kotlin functional-programming arrow-kt


    【解决方案1】:

    您可以使用 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> { ... }
    

    如果EitherRight,这里bind() 将解开EitherNewObject,或者如果找到LeftConvertError,它将退出either.eager 块。这里我们使用eager { } 变体,因为我们立即将其分配给val。主要的suspend fun either { } 块支持内部的suspend 函数,但它本身也是suspend 函数。

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

    import arrow.core.traverseEither
    
    eithers.traverseEither(::convert) 
    

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

    import arrow.fx.coroutines.parTraverseEither
    
    eithers.parTraverseEither(Dispatcheres.IO, ::convert) 
    

    【讨论】:

      【解决方案2】:

      这是一个常见的,您正在寻找的内容称为traverse。类似于map,只是它按照内容的聚合规则收集结果。

      所以,list.k().traverse(Either.applicative()) { convert(it) } 将返回 Either.Left 是任何返回 Left 的操作,否则 Right&lt;List&lt;

      【讨论】:

      • 我不熟悉.k() 的作用,你能解释一下它在做什么以及为什么需要它吗?我很欣赏简洁的答案。
      【解决方案3】:

      arrow.core.IterableKt#sequenceEither怎么样?

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

      【讨论】:

        猜你喜欢
        • 2013-03-28
        • 1970-01-01
        • 1970-01-01
        • 2023-04-04
        • 1970-01-01
        • 2021-12-11
        • 1970-01-01
        • 1970-01-01
        • 2017-09-20
        相关资源
        最近更新 更多