我是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
变量,以确保其匹配其期望的返回类型?
谢谢。
答案 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]
}