Search code examples
scalamonadsscalazmonad-transformers

Combining List, Future and Option in for-comprehension - scalaz


I've got following problem:

val sth: Future[Seq[T, S]] = for {
  x <- whatever: Future[List[T]]
  y <- x: List[T]
  z <- f(y): Future[Option[S]]
  n <- z: Option[S]
} yield y: T -> n: S

I would want to make this code to work(I guess everyone understands the idea as I've added types).

By "to work" I mean, that I would want to stay with the for-comprehension structure and fulfil expected types in the end. I know there are "ugly" ways to do it, but I want to learn how to do it pure :)

As I read the internet I've reached the conclusion that my problem may be solved by the monad transformers & scalaz. Unfortunately, I couldn't find an example to help understand better how should I proceed.

At the moment I've tried scalaz and Eff monad libs, but I guess I still don't understand how it works because I couldn't solve my problem.

I will be grateful for any help.

EDIT: It supposed to be future of sequence, also regarding the "whatever" I get it as a parameter of the function, sorry for misleading you


Solution

  • You could do something like what you need using the scalaz ListT monad transformer

     object Test {
       import scalaz._
       import ListT._
       type T = String
       type S = Int
       val whatever: Future[List[T]] = ??? // you get this somewhere
       def f(y: T): Future[Option[S]] = ??? // function that returns future of option
    
       val sth: Future[List[(T, S)]] = (for {
         y <- listT(whatever) 
         // you cannot mix list and option, but you can convert the option to a list of 1 item
         n <- listT(f(y).map(_.toList)) 
       } yield y -> n).run
     }
    

    N.B.: Since you start with a future, you cannot return a Seq[(T,S)], you can only have a future. You have to call Await.result if you want to block and get the result.