I want to read a list of files using cats-effect's IO monad like this:
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 ???
Now to continue my computation inside the for-yield-construction I'd like to transform my List[IO[Either[CouldNotReadFromFileError, String]]]
into a IO[List[Either[CouldNotReadFromFileError, String]]]
. I know that I can probably do something like this using cat's traverse, but cannot figure out how exactly. Any help is greatly appreciated.
sequence
is enough for what you want:
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 {
???
}
}