Implementing real "forall" in scala futures list

I use scala frames (2.12) to apply a division and conquest approach for a complex task. Here is some (simplified) context:

def solve(list: List[Int], constraints: Con): Future[Boolean] =
  Future.unit.flatMap{ _ =>
    //positive case
    if(list.isEmpty) Future.successful(true)

    //negative case
    else if(someTest(constraints)) Future.successful(false)

    //divide and conquer
    else {
      //split to independent problems, according to constraints
      val components: List[List[Int]] = split(list,constraints)

      //update the constraints accordingly (heavy computation here)
      val newConstr: Con = updateConstr(...)

      val futureList = components.map(c => solve(c,newConstr))
      allTrue(Future.successful(true), futureList)
    }
  }

This recursive function accepts a list of integer variables and an object Conrepresenting constraint problems, and generates many independent subtasks during each call.

The relevant part of my question is the challenge allTrue. If I solved the problem sequentially, I would write components.forall(c => solve(c,newConstr)). However, in the parallel version, I have something like this that does not stop the calculation in the first case encountered false.

//async continuation passing style "forall"
def allTrue(acc: Future[Boolean], remaining: List[Future[Boolean]]): 
  Future[Boolean] = {
    remaining match {
      case Nil => acc
      case r :: tail => acc.flatMap{ b => 
        if(b) allTrue(r,tail)
        else{
          //here, it would be more efficient to stop all other Futures
          Future.successful(false)
        }
      }
    }
  }

, , scala, , , , .

, forall ?

+4
1

Future.traverse

val all:Future[List[Boolean]] = Future.traverse(components)(c => solve(c, newConstr)
val forAll:Future[Boolean] = all.map(_.forall(identity))

Observable. , False, ,

+2

Source: https://habr.com/ru/post/1694173/


All Articles