Skip to content

Instantly share code, notes, and snippets.

@gclaramunt
Last active January 11, 2019 20:06
Show Gist options
  • Save gclaramunt/74698bf8881899f42ad77916c2716946 to your computer and use it in GitHub Desktop.
Save gclaramunt/74698bf8881899f42ad77916c2716946 to your computer and use it in GitHub Desktop.
foldMap and secuence
object FutureUtils {
/**
* Serialises the futures so they execute one after another
* Future.sequence still runs all futures at the same time
*/
def sequence[A, B](l: Iterable[A])(fn: A ⇒ Future[B])(implicit ec: ExecutionContext): Future[Iterable[B]] =
foldM(l, ListBuffer.empty[B]) { (xs, x) => fn(x).map(xs :+ _) }
/**
* specialized Iterable's foldM to Future (see Cats)
* serializes the future application threading an intermediate result
*/
def foldM[A, B](l: Iterable[A], z: B)(fn: (B, A) => Future[B])(implicit ec: ExecutionContext): Future[B] = {
l.foldLeft(Future(z)) {
(previousFuture, next) =>
for {
previousResults <- previousFuture
next <- fn(previousResults, next)
} yield next
}
}
/**
No need to specialize if you have a monad
*/
trait Monad[F[_]] {
def pure[A](a: A): F[A]
def flatMap[A,B](ma: F[A])(f: A => F[B]): F[B]
}
def foldM[M[_]: Monad, A, B](l: Iterable[A], z: B)(fn: (B, A) => M[B]): M[B] = {
val m = implicitly[Monad[M]]
l.foldLeft(m.pure(z)) {
(previousM, next) =>
m.flatMap(previousM){ previousResults => fn(previousResults, next)}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment