首页 > 解决方案 > 带箭头:如何应用 (X)->IO 类型的转换到序列类型的数据获取 IO>?

问题描述

我正在使用 Arrow.kt 学习函数式编程,打算遍历路径层次结构并散列每个文件(并做一些其他事情)。强迫自己尽可能多地使用功能概念。

假设我data class CustomHash(...)已经在代码中定义了一个。下面会参考。

首先,我需要通过走路径来构建一系列文件。这是一个不纯/有效的函数,因此应该用IOmonad 将其标记为:

fun getFiles(rootPath: File): IO<Sequence<File>> = IO {
   rootPath.walk() // This function is of type (File)->Sequence<File>
}

我需要阅读文件。再次,不纯,所以这被标记为IO

fun getRelevantFileContent(file: File): IO<Array<Byte>> {
   // Assume some code here to extract only certain data relevant for my hash
}

然后我有一个计算哈希的函数。如果它需要一个字节数组,那么它是完全纯的。之所以这样做,suspend是因为执行起来会很慢:

suspend fun computeHash(data: Array<Byte>): CustomHash {
   // code to compute the hash
}

我的问题是如何以功能性的方式将所有这些链接在一起。

fun main(rootPath: File) {
   val x = getFiles(rootPath) // IO<Sequence<File>>
      .map { seq -> // seq is of type Sequence<File>
         seq.map { getRelevantFileContent(it) } // This produces Sequence<IO<Hash>>
      }
   }
}

现在,如果我尝试这个,xIO<Sequence<IO<Hash>>>. 我很清楚为什么会这样。

有什么办法可以Sequence<IO<Any>>变成IO<Sequence<Any>>? 我想这本质上可能是术语不精确,采用在它们自己的协程中执行的代码块并在同一个协程上运行所有代码块?

如果 Sequence 不存在,我知道IO<IO<Hash>>可以在那里IO<Hash>使用 a flatMap,但Sequence当然没有 IO 功能的扁平化。

Arrow 的文档有很多“TODO”部分,并且可以非常快速地跳转到假定大量中级/高级函数式编程知识的文档。它对这个问题并没有真正的帮助。

标签: kotlinfunctional-programmingarrow-kt

解决方案


First you need to convert the Sequence to SequenceK then you can use the sequence function to do that.


import arrow.fx.*
import arrow.core.*
import arrow.fx.extensions.io.applicative.applicative

val sequenceOfIOs: Sequence<IO<Any>> = TODO()

val ioOfSequence: IO<Sequence<Any>> = sequenceOfIOs.k()
    .sequence(IO.applicative())
    .fix()

推荐阅读