Folding a sequence with a binary operation that returns Future
Asked Answered
D

3

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 ?

Disapprobation answered 19/6, 2019 at 9:30 Comment(0)
C
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?

Comportment answered 19/6, 2019 at 10:21 Comment(0)
D
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)
Dinahdinan answered 19/6, 2019 at 10:10 Comment(1)
Thanks. Good example of why cats are useful but I would prefer a plain Scala solution for now.Disapprobation
T
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)
Turntable answered 19/6, 2019 at 10:22 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.