Using typelevel/cats flatTraverse for different Functors

Viewed 1151

I have been trying to use more abstract functional programming concepts like those from typelevel/cats for Scala.

In this specific case I am trying to eliminate the need to call map(_.flatten) after traversing some Futures.

Using the standard library it would look something like this:

def stdExample[T](things: Seq[T]): Future[Seq[T]] = {
  Future.traverse(things)(futureMaybeThings[T]).map(_.flatten)
}
def futureMaybeThings[T](thing: T): Future[Option[T]] = ???

I tried using flatTraverse from typelevel/cats but the best I could get was this:

def catsExample[T](things: Seq[T]): Future[Seq[T]] = {
  things.toList.flatTraverse(futureMaybeThings[T](_).map(_.toList))
}

The call to things.toList is required to get the Traversable, I can live with that one.

Since flatTraverse requires f to be C => G[F[B]] (where both C and B are T, G is Future and F is List), futureMaybeThings doesn't match without first transforming the result with map(_.toList). This ends up being worse than the other solution.

It is possible to create a function that works just on Future and TraversableOnce (since there is an implicit conversion for Option[A] => TraversableOnce[A]. Such an implementation might be like:

def flatTraverse[A, B[_], C, M[X] <: TraversableOnceWithFlatten[X, M]](in: M[A])
                                                                (fn: A => Future[B[C]])
                                                                (implicit cbf: CanBuildFrom[M[A], B[C], M[B[C]]],
                                                                 asTraversable: B[C] => TraversableOnce[C],
                                                                 executor: ExecutionContext): Future[M[C]] = {
  Future.traverse(in)(fn).map(_.flatten)
}

This now works how I want:

def customExample[T](things: Seq[T]): Future[Seq[T]] = {
  flatTraverse(things)(futureMaybeThings[T])
}

Is there a way to achieve this same thing with typelevel/cats?

Bonus: If not then what would the signature of such a function look like?

0 Answers
Related