Search code examples
scalamonadsfor-comprehension

Scala: for-comprehension with recursive Future


The task is to realise recursive method, which returns Future

def recursive (result:List[Result], attempt: Int):Future[Seq[Result]] = attempt match {
   case a if a < 3 => { 
       for {
            res <- retrive()
           } yield {
               if ((result:::res).size > 20) res
               else recursive (result:::res, attempt + 1)          
           }
   }
   case => Future(Seq.empty)
}

And due to this part ("else recursive (result:::res, attempt + 1)" ) code failed with error, as it expects Future[Seq[Result]], but in fact return Future[Object].

As I understand, the problem is that expression inside yield-block must return Seq[Result] for the subsequent wrapping by Monad in Future. But "recursive (result:::res, attempt + 1)" return Future. So, instead of the expected Seq[Result] yield contain Future[Seq[Result]].

It there any way to work around this problem?


Solution

  • The trick is to wrap the value you are returning in the terminal case into a future, so that the types match for both cases.

    You don't really need a for-comprehension here, it would read a lot better without it IMO:

       retrieve.flatMap { 
          case r if r.size + result.size > 20 => Future.successful(result:::r) // you are not prepending result in your snippet, I think, it's a bug ...
          case r => recursive (result:::r, attempt + 1)  
       }
    

    If you are partial to for-comprehension for some reason, you can still use it, just need to move most of the yield clause inside the for:

        for {
           res <- retrieve()
           out <- if (res.size() + result.size() > 20) Future.successful(result:::res) 
                  else recursive (result:::res, attempt + 1) 
         } yield out