如何使用Scala和Cats从列表[F [String]]转到F [List [String]]?

时间:2018-10-14 15:06:02

标签: scala scala-cats

我是Cat的新手,我不知道该如何克服这种情况。在下面的代码中:

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 :(得分:7)

这种转换是通过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。您可以在the cats documentation中阅读有关为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]
}