I have a function:
def mapIt(id: Int): F[String]
What is the best way to map a collection using it, if the result is used in constructor of a case class? I currently do something like this:
List(1, 2, 3, 4).map( id => mapIt(id).map(SomeCaseClass(id, _))).toList.sequence
CodePudding user response:
You can map some Monad[Int] into Monad[SomeCaseClass] just using map function (if F is Monad then it can be converted to List using ListInstances.catsStdInstancesForList from cats.instances.list). After that all you need is just flatMap your list of Int into list of SomeCaseClass:
import cats.Monad
import cats.instances.list._
import scala.language.higherKinds
case class SomeCaseClass(id: Int, name: String)
def mapIt[F[_]: Monad](id: Int): F[String] = Monad[F].pure((id 10).toString)
List(1, 2, 3, 4).flatMap(id => mapIt(id).map(x => SomeCaseClass(id, x)))
//List(
// SomeCaseClass(1,11),
// SomeCaseClass(2,12),
// SomeCaseClass(3,13),
// SomeCaseClass(4,14)
//)
More detailed explanation
in function mapIt:
def mapIt[F[_]: Monad](id: Int): F[String]
compiler expect some F[_] which should have some Monad implicit.
When you call mapIt inside flatMap function, compiler looking for some Monad over the Int:
List(1, 2, 3, 4).flatMap{
id => mapIt(id) // looking for Monad[Int]
}
and found it in the imported instances:
import cats.instances.list._
From ListInstances:
implicit val catsStdInstancesForList: Traverse[List] with Alternative[List] with Monad[List] with CoflatMap[List] =
new Traverse[List] with Alternative[List] with Monad[List] with CoflatMap[List] { ... }
after it's just working with common Monad and map Int into SomeCaseClass. In the end it's just flatten List of SomeCaseClasses into.
