如何使用Scala和Cats将List[F[String]]转换为F[List[String]]?

4

我是一名新手,对于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变量转换为其期望的返回类型?

谢谢。

1个回答

14

使用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]]
}

在Cats中,每个具有Monad的类型也都具有Applicative,因此Example类即使是用Monad也可以工作。

但反之不然。一些类型只有一个Applicative实例。其中最显著的是Validated。你可以在Cats文档中阅读有关为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]
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接