I'm looking for the most elegant implementation of
import scalaz.zio.Task
def combineTasks[A, B, C, D](task1: Task[Option[A]],
task2: Task[Option[B]],
task3: Task[Option[C]])
(f: (A, B, C) => D)
: Task[Option[D]]
using
scalaz-zio-interop-cats
and cats
scalaz-zio-interop-scalaz7x
and scalaz7x
The solutions should generalize well to n arguments.
After getting some help and doing research, I found the following implementations, that seem the most elegant to me so far:
1. Using no additional dependencies:
def combineTasks[A, B, C, D](task1: Task[Option[A]],
task2: Task[Option[B]],
task3: Task[Option[C]])
(f: (A, B, C) => D)
: Task[Option[D]] = {
for {
t1 <- task1
t2 <- task2
t3 <- task3
} yield {
(t1, t2, t3) match {
case (Some(t1), Some(t2), Some(t3)) => Some(f(t1, t2, t3))
case _ => None
}
}
}
2. Using scalaz-zio-interop-cats
and cats
:
def combineTasks[A, B, C, D](task1: Task[Option[A]],
task2: Task[Option[B]],
task3: Task[Option[C]])
(f: (A, B, C) => D)
: Task[Option[D]] = {
import cats.implicits.catsStdInstancesForOption
import cats.Apply
import scalaz.zio.interop.catz._
Apply[Task].compose[Option].map3(task1, task2, task3)(f)
}
See mapN over composed Apply for a related discussion.
3. Using scalaz-zio-interop-scalaz7x
and scalaz7x
:
def combineTasks[A, B, C, D](task1: Task[Option[A]],
task2: Task[Option[B]],
task3: Task[Option[C]])
(f: (A, B, C) => D): Task[Option[D]] = {
import scalaz.Apply
import scalaz.std.option._
import scalaz.zio.interop.scalaz72._
Apply[Task].compose[Option].apply3(task1, task2, task3)(f)
}