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 SomeCaseClass
es into.