5

Suppose I've got a function op: (Int, Int) => Future[Int] and need to write a new function foo :

def foo(xs: Seq[Int], 
        zero: Int, 
        op: (Int, Int) => Future[Int]): Future[Int] = ???

foo should work as foldLeft and apply op sequentially to all elements in xs, e.g.:

val op: (Int, Int) => Future[Int] = (x, y) => Future(x + y)
val xs = (1 to 10)
val fut = foo(xs, 0, op) // should return Future of 55
fut.value // Some(Success(55))

How would you implement foo ?

Michael
  • 41,026
  • 70
  • 193
  • 341

3 Answers3

6

I'm not sure why the other answer was deleted - but with plain Scala this works for me:

 def foo(xs: Seq[Int], zero: Int, op: (Int, Int) => Future[Int]): Future[Int] =  

    xs.foldLeft(Future.successful(zero))((a, b) => a.flatMap(op(_, b)))

Do I miss something?

pme
  • 14,156
  • 3
  • 52
  • 95
5

Try foldM from cats:

import cats._
import cats.implicits._

def foo(xs: Seq[Int], zero: Int, op: (Int, Int) => Future[Int]): Future[Int] =
  Foldable[List].foldM(xs.toList, zero)(op)
Mario Galic
  • 47,285
  • 6
  • 56
  • 98
  • Thanks. Good example of why `cats` are useful but I would prefer a plain Scala solution for now. – Michael Jun 19 '19 at 11:55
2

Without using an external library:

Implement a "special" foldLeft:

def foldLeft[Int](xs: Seq[Int], z: Int)(op: (Int, Int) => Future[Int]): Future[Int] = {
 def f(xs: Seq[Int], accF: Future[Int]): Future[Int] = xs match {
   case Seq()   => accF
   case x +: xs => accF.flatMap(acc => f(xs, op(acc, x)))
 }

 f(xs, Future.successful(z))

}

And using it:

def foo(xs: Seq[Int], 
    zero: Int, 
    op: (Int, Int) => Future[Int]): Future[Int] = foldLeft(xs, zero)(op)
Gal Naor
  • 2,397
  • 14
  • 17