如何使用 Scala 和 Cats 从 List[OF[String]] 到 F[List[String]]?

How to go from a List[F[String]] to F[List[String]] using Scala and Cats?

我是 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]
}

如何在 saveAll 函数中转换 result 变量,以确保它符合预期的 return 类型?

谢谢。

这种变换是用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 类型 class 中的 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 class 甚至可以与 Monad 一起使用。

但反之则不然。有些类型只有一个 Applicative 实例。其中最值得注意的是 Validated。您可以在 the cats documentation.

中阅读有关为 Validated 实施 Monad 的问题的更多信息

因此,如果您改为请求 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]
}