Этот вид преобразования выполняется с помощью операции 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
.Вы можете прочитать больше о проблеме с реализацией 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]
}