Как использовать Traverse для запуска списка эффектов - PullRequest
1 голос
/ 12 февраля 2020

У меня есть такая функция:

 def getFile(url: String): EitherT[Future, Error, ByteString]

Используется EitherT для кошек.

Я вызываю эту функцию с помощью другой функции, подобной этой:

def getAllFiles(urls: List[String]): EitherT[Future, Error, List[ByteString]] = {
    urls.map(f => getFile(f).value)
  }

Это не работает, поскольку я получаю несоответствие типов:

found   : List[scala.concurrent.Future[Either[Error,akka.util.ByteString]]]
[error]  required: cats.data.EitherT[scala.concurrent.Future,Error,List[akka.util.ByteString]]

Независимо от того, что я пытаюсь, я не могу это скомпилировать. По сути, я хочу запустить getFile для каждого URL и загрузить файл в Bytestring.

1 Ответ

3 голосов
/ 12 февраля 2020

Это работает:

import cats.data.EitherT
import cats.effect.IO
import cats.implicits._

type Error = String
type ByteString = Array[Byte]

def getFile(url: String): EitherT[IO, Error, ByteString] = ???

def getAllFiles(urls: List[String]): EitherT[IO, Error, List[ByteString]] =
  urls.traverse(getFile)

Но это не так:

def getFile(url: String): EitherT[Future, Error, ByteString] = ???

def getAllFiles(urls: List[String]): EitherT[Future, Error, List[ByteString]] =
  urls.traverse(getFile)

Причина в том, что traverse ожидает Аппликативное от вложенного эффекта , который cats обеспечивает IO, но не для Future.


Итак, причина в том, что из-за нетерпеливой и кэшированной природы Future Мы не можем реально рассуждать о его поведении. Так что cats не предоставляет экземпляры для этого.
Вы можете предоставить свои Applicative для Future ... но, ИМХО, было бы проще просто адаптировать код с использованием IO.fromFuture и io.unsafeToFuture()

...