使用Arrow:如何将(X)-> IO <Y>类型的转换应用于Sequence <X>类型的数据以获取IO <Sequence <Y >>?

时间:2019-12-10 17:48:33

标签: kotlin functional-programming arrow-kt

我正在使用Arrow.kt学习函数式编程,打算遍历路径层次结构并哈希每个文件(并执行其他操作)。强迫自己尽可能多地使用功能概念。

假设我已经在代码中定义了data class CustomHash(...)。它将在下面引用。

首先,我需要通过遍历路径来构建文件序列。这是一个不完善的功能,因此应使用IO monad进行标记:

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>>
      }
   }
}

现在,如果我尝试这样做,x的类型为IO<Sequence<IO<Hash>>>。我很清楚为什么会这样。

是否有某种方法可以将Sequence<IO<Any>>变成IO<Sequence<Any>>?我想从本质上讲,可能是术语不精确,获取在自己的协程中执行的代码块,而是全部在同一协程上运行这些代码块?

如果序列不存在,我知道IO<IO<Hash>>可以通过在其中使用IO<Hash>flatMap,但是Sequence当然没有展平IO功能。

Arrow的文档包含许多“ TODO”部分,并且可以非常快速地跳转到假定您具有许多中级/高级功能编程知识的文档中。对于这个问题,它并没有真正的帮助。

1 个答案:

答案 0 :(得分:1)

首先,您需要将“100 200 + 2 / 5 * 7 + \n”转换为Sequence,然后才能使用SequenceK函数。

sequence