我正在使用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”部分,并且可以非常快速地跳转到假定您具有许多中级/高级功能编程知识的文档中。对于这个问题,它并没有真正的帮助。
答案 0 :(得分:1)
首先,您需要将“100 200 + 2 / 5 * 7 + \n”
转换为Sequence
,然后才能使用SequenceK
函数。
sequence