将IO列表转换为列表的IO

时间:2019-02-13 13:54:01

标签: scala io functional-programming scala-cats

我想使用cats-effect的IO monad读取文件列表,如下所示:

def readFile(file: File): IO[Either[CouldNotReadFromFileError, String]] = ???

// lists all the files I want to read
// returns an Either b/c this might encounter i/o problems
def findFiles(): IO[Either[Throwable, Array[File]]] = ???

// reads all files and saves their content in an Array[String]
// ignores files it could not read or find
def readFiles(): IO[Array[String]] = for {
    filesE <- listFiles
    files = filesE match {
      case Left(err) =>
        log.error("An error happened while reading files: " + err.getMessage)
        List[File]()
      case Right(fs) => fs.toList.map(readFile)
    }
    // files has type: List[IO[Either[CouldNotReadFromFileError, String]]]
    // to continue here I'd like to have a: IO[List[Either[CouldNotReadFromFileError, String]]]
    ???
} yield ???

现在继续在for-yield-construction中进行我的计算,我想将List[IO[Either[CouldNotReadFromFileError, String]]]转换为IO[List[Either[CouldNotReadFromFileError, String]]]。我知道我可以使用cat's traverse来做类似的事情,但是无法弄清楚它的精确程度。任何帮助将不胜感激。

1 个答案:

答案 0 :(得分:1)

sequence足以满足您的需求:

import java.io.File
import cats.effect.IO
import cats.implicits._

final class CouldNotReadFromFileError extends RuntimeException("message")

object TestTest {
  def readFile(file: File): IO[Either[CouldNotReadFromFileError, String]] = ???

  def findFiles: IO[Either[Throwable, Array[File]]] =
    ???

  // reads all files and saves their content in an Array[String]
  // ignores files it could not read or find
  def readFiles(): IO[Array[String]] =
    for {
      filesE <- findFiles
      files = filesE match {
        case Left(err) =>
          List.empty
        case Right(fs) =>
          fs.toList.map(readFile)
      }
      // The type ascription below is just for demonstration purposes.
      // You don't need to keep it there.
      a <- files.sequence: IO[List[Either[CouldNotReadFromFileError, String]]]
    } yield {
      ???
    }
}