首页 > 解决方案 > How to go from a List[F[String]] to F[List[String]] using Scala and Cats?

问题描述

I'm new to Cats and I don't know how to overcome this situation. In the code bellow:

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

How do I transform the result variable, in the saveAll function, to make sure it matches its expected return type?

Thanks.

标签: scalascala-cats

解决方案


这种转换是通过以下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从 typeclass中的方法签名可以看出,Traverse它需要一个 的实例Applicative,而不是一个Monad

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

在猫中,每种类型都有 aMonad也有一个Applicative,因此Example该类甚至可以使用Monad.

但反过来是不正确的。有些类型只有一个Applicative实例。其中最值得注意的是Validated。您可以在cat 文档中阅读有关实现Monadfor问题的更多信息。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]
}

推荐阅读