组成 scalaz io 效果对象

Composing scalaz io effect objects

我正在尝试将 scalaz 的 ioeffect IO[E,A] monad 用于一段非常有效的代码。

我试图用 IO[E,A] 在高层次上重写的代码需要一些关于存储在云中的文件的元数据。代码尝试:

  1. 下载文件
  2. 从文件中提取字符串
  3. 构建一个包含文件文本内容的 pojo
  4. 将 pojo 提交给某些 queue/restful 服务

步骤的细节并不是那么重要,但我想做的是按照以下方式做一些事情:

def processShareActivity(fileObject: FileObject): IO[ProcessFileFailure, IndexResponse] = {
    for {
        file <- downloadFile (fileObject)
        text <- extractText (file)
        searchFileObject <- IO.point(buildSearchFileObject (fileObject, file, text))
        indexedResponse <- indexSearchFileObject (searchFileObject)
    } yield indexedResponse
}

def indexSearchFileObject(fileObject: SearchFileObject): IO[IndexFailure, IndexResponse] = ???

def buildSearchFileObject(fileObject: FileObject, file: File, str: String): SearchFileObject = ???

def extractText(file: File): IO[ExtractionFailure, String] = ???

def downloadFile(fileObject: FileObject): IO[DownloadFileFailure, File] = ???

问题是 IO[E,A]IO[F,B] 的实例似乎没有组合。也就是说,因为例如 downloadFile 的 IO 签名 returns DownloadFileFailureextractText returns ExtractionFailure,那些单子不能似乎无法理解 for

有没有一种简单的方法可以让我的顶级 for 理解组合成 IO[ProcessFileFailure, IndexResponse],其中 ProcessFileFailure 是围绕不同对象的某种包装失败对象子方法中可能发生的故障类型?

不幸的是,您确实需要一种方法将这些错误统一为一个常见错误:

例如:

sealed trait ProcessFileFailure
object ProcessFileFailure {
   case class Index(e: IndexFailure) extends ProcessFileFailure
   case class Extraction(e: ExtractionFailure) extends ProcessFileFailure
   case class Download(e: DownloadFileFailure) extends ProcessFileFailure
}

你的理解力会变成:

for {
        file <- downloadFile (fileObject).leftMap(ProcessFileFailure.Download)
        text <- extractText (file).leftMap(ProcessFileFailure.Extraction)
        searchFileObject <- IO.point(buildSearchFileObject (fileObject, file, text))
        indexedResponse <- indexSearchFileObject (searchFileObject).leftMap(ProcessFileFailure.Index)
    } yield indexedResponse

它很笨拙,但它确实具有能够存储出错的所有内容以及出错发生的确切上下文的优势。