Как перейти от List [F [String]] к F [List [String]], используя Scala и Cats? - PullRequest
0 голосов
/ 14 октября 2018

Я новичок в Cats и не знаю, как преодолеть эту ситуацию.В приведенном ниже коде:

class Example[F[_]] {
  import cats._
  import cats.data._
  import cats.syntax.all._

  def saveAll(list: List[String])(implicit M: Monad[F]): F[List[String]] = {
    val result: List[F[String]] =
      list.map(saveOne)
  }

  def saveOne(s: String)(implicit M: Monad[F]): F[String] = s"Saved $s".pure[F]
}

Как преобразовать переменную result в функцию saveAll, чтобы она соответствовала ожидаемому типу возвращаемого значения?

Спасибо.

1 Ответ

0 голосов
/ 14 октября 2018

Этот вид преобразования выполняется с помощью операции traverse:

class Example[F[_]] {
  import cats._
  import cats.implicits._

  def saveAll(list: List[String])(implicit M: Monad[F]): F[List[String]] = 
    list.traverse(saveOne)

  def saveOne(s: String)(implicit M: Monad[F]): F[String] = 
    s"Saved $s".pure[F]
}

. Как видно из сигнатуры метода traverse в классе типов Traverse, требуется экземпляр Applicative, а не Monad:

trait Traverse[F[_]] {
  def traverse[G[_]: Applicative, A, B](fa: F[A])(f: A => G[B]): G[F[B]]
}

У кошек каждый тип, имеющий Monad, также имеет Applicative, поэтому класс Example работает даже с Monad,

Но обратное неверно.Некоторые типы имеют только экземпляр Applicative.Наиболее заметным из них является Validated.Вы можете прочитать больше о проблеме с реализацией Monad для Validated в документации котов .

Так что этот код будет более общим, если вы запросите экземпляр Applicative вместо:

class Example[F[_]] {
  import cats._
  import cats.implicits._

  def saveAll(list: List[String])(implicit M: Applicative[F]): F[List[String]] = 
    list.traverse(saveOne)

  def saveOne(s: String)(implicit M: Applicative[F]): F[String] = 
    s"Saved $s".pure[F]
}
...