2

I have a method readHeader which takes one argument and returns Task[List[Header]] and another method calls for multiple ids and returns List[Task[List[EquipmentHeader]]]. How to make a return of Task[List[List[Header]]] compatible with multiple id read function.

trait M1{
  def readHeader(id: String): Task[List[Header]]
}

def read(ids: List[String])(implicit m1:M1):Task[List[List[Header]]] = {
    if (ids.isEmpty) {
      Task(List.empty)
    } else {
         ids.map(m1.readHeader(_)) //List[Task[List[Header]]]
    }
  }
Sumeet Kumar Yadav
  • 11,912
  • 6
  • 43
  • 80
  • I believe you should be able to get what you want using `ids.traverse(m1.readHeader)` if you get a not method error you would need to `import cats.implicits._` first. – Luis Miguel Mejía Suárez Dec 18 '19 at 17:35
  • Can you explain what cats library does and if not using cats, how it can be done in scala using flat map or any other API – Sumeet Kumar Yadav Dec 18 '19 at 17:51
  • If you are using **Monix** I am pretty sure you are already using **cats** _(transitively)_ and if not, then there isn't really any reason to do not do it, both libraries work very well together. And while you may implement this using standard methods, it would be somewhat difficult. I would recommend you read [**this**](https://underscore.io/books/scala-with-cats/) book to understand the `Traversable` abstraction _(and many others)_. – Luis Miguel Mejía Suárez Dec 18 '19 at 17:54
  • can you explain if not using cats how to do – Sumeet Kumar Yadav Dec 18 '19 at 18:01

2 Answers2

2

You can use traverse from cats:

import cats.implicits._

ids.traverse(m1.readHeader) // Task[List[List[Header]]]
Yuval Itzchakov
  • 146,575
  • 32
  • 257
  • 321
2

Here is a naive implementation of traverse for just Task and List.
But again, I insist, there is no reason for not using the one defined in cats.

def traverse[A, B](list: List[A])(f: A => Task[B]): Task[List[B]] = {
  @annotation.tailrec
  def loop(remaining: List[A], acc: Task[List[B]]): Task[List[B]] =
    remaining match {
      case a :: as =>
        loop(
          remaining = as,
          acc = for {
            b <- f(a)
            bs <- acc
          } yield b :: bs
        )

      case Nil =>
        acc.map(_.reverse)
    }
  loop(remaining = list, acc = Task.pure(List.empty))
}