I have the following methods:
trait Tr[F[_]]{
def getSet(): F[Set[String]]
def checksum(): F[Long]
def value(): F[String]
def doRun(v: String, c: Long, s: Set[String]): F[Unit]
}
now I want to write the following for comprehension:
import cats._
import cats.data.OptionT
import cats.implicits._
def fcmprhn[F[_]: Monad](F: Tr[F]): OptionT[F, Unit] =
for {
set <- OptionT {
F.getSet() map { s =>
if(s.nonEmpty) Some(s) else None
}
}
checksum <- OptionT.liftF(F.checksum())
v <- OptionT.liftF(F.value())
_ <- OptionT.liftF(F.doRun(v, checksum, set))
//can be lots of OptionT.liftF here
} yield ()
As you can see there is too much of OptionT
boilerplate. Is there a way to avoid it?
I think I can make use of F ~> OptionT[F, ?]
. Can you suggest something?
One approach could be to nest the "F only" portion of the for-comprehension within a single liftF
:
def fcmprhn[F[_]: Monad](F: Tr[F]): OptionT[F, Unit] =
for {
set <- OptionT {
F.getSet() map { s =>
if(s.nonEmpty) Some(s) else None
}
}
_ <- OptionT.liftF {
for {
checksum <- F.checksum()
v <- F.value()
_ <- F.doRun(v, checksum, set)
// rest of F monad for-comprehension
} yield ()
}
} yield ()