Reputation: 237
I am trying to write a Value Class to add functionality to anything that implements Seq[_]
and allow it to make batch calls that return a Future[_]
(specifically, I am using it to make batch REST calls).
final class BatchedList[A, C[X] <: Seq[X]](val targetList: C[A]) extends AnyVal {
def batchRequests[B](batchSize: Int)(runner: Seq[A] => Seq[Future[Either[Result, B]]])
(implicit bf: CanBuildFrom[C[A], Either[Result, B], C[Either[Result, B]]]): Future[Either[Result, C[B]]] = {
targetList.grouped(batchSize).foldLeft(Future.successful(bf(targetList))) { (results, set) =>
results flatMap { responses =>
Future.sequence(runner(set)).map(responses ++=)
}
} map {
_.result().sequenceU
}
}
}
However, I can't get this to compile. I keep receiving the compiler error
value sequenceU is not a member of type parameter C[Either[play.api.mvc.Result,B]]
I've imported both scalaz._
and Scalaz._
, and I know they've provided a Traverse[_]
for my use case (which is List[_]
in this example). I'm pretty sure this is some sort of implicit resolution issue with the types, but I'm stumped on how to proceed forward resolving it.
Upvotes: 0
Views: 121
Reputation: 8932
I believe that this happens because Scalaz doesn't provide typeclass instances for Seq
but instead for IndexedSeq
and List
. As such, you'll need to provide the Traverse
instance yourself (note the additional implicit argument C
to batchRequests
):
final class BatchedList[A, C[X] <: Seq[X]](val targetList: C[A]) extends AnyVal {
def batchRequests[B](batchSize: Int)(runner: Seq[A] => Seq[Future[Either[Result, B]]])
(implicit bf: CanBuildFrom[C[A], Either[Result, B], C[Either[Result, B]]], C: Traverse[C]): Future[Either[Result, C[B]]] =
targetList.grouped(batchSize).foldLeft(Future.successful(bf(targetList))) { (results, set) =>
results flatMap { responses =>
Future.sequence(runner(set)).map(responses ++=)
}
} map {
_.result().sequenceU
}
}
As you can see, this will return a sequence type corresponding to the type provided as C
:
scala> def run[A](s: Seq[A]): Seq[Future[Either[Result, A]]] =
| s.map(i => Future.successful(Right(i)))
run: [A](s: Seq[A])Seq[scala.concurrent.Future[Either[Result,A]]]
scala> :t new BatchedList(List(1,2,3)).batchRequests(1)(run)
scala.concurrent.Future[Either[Result,List[Int]]]
scala> :t new BatchedList(Vector(1,2,3)).batchRequests(1)(run)
scala.concurrent.Future[Either[Result,scala.collection.immutable.Vector[Int]]]
If you always want it to return a Seq
it's a simple matter of an upcast.
Upvotes: 1