Let's say we have this:
def join[A, B](a: A, b: B)
def join[A, B, C](a: A, b: B, c: C) // etc
Basically a lot of overloaded methods for up to 20 type arguments.
And then the following which is creating a K-list by enforcing an unary type constraint on the HList such that all inner elements are of type Task[_].
class Test(L <: HList : *->*[Task]#λ](val deps : L = HNil)
Is it possible to convert the deps to a Task[A1, A2, A3] etc where the A1, A2, A3 are the inner types of the HList?
So for:
val hls = Task(1) :: Task("string") :: Task9(true) :: HNil
Retrieve a:
Task[(Int, String, Boolean)]
And do this for any number of arguments? I can convert a Task[A], Task[B] to a Task[A, B] for any number of arguments already, just need to get from HList to varargs or similar.
From Scala's perspective those
joinmethods don't have anything in common but their name, so it's not really possible to use them in this context without a lot of boilerplate (or a custom macro). Instead it's possible to use thejoinon Twitter'sFutureitself repeatedly. You can do this by creating a new type class:This type class will witness that an hlist
Lis made up entirely of futures, and it will give us a way to sequence those futures into aFuture[T], whereTis the tuple made up of the types inside of each of the futures inL(the*->*gives us the first part of this, but doesn't support the second, or even any way to do the second part at all conveniently).The companion object does all the interesting work:
We're using induction here—first we describe how to sequence
HNil(our base case), and then we describe how to sequenceFuture[H] :: Tgiven that we know how to sequenceT.Next we'll define a method to make this easy to use:
And then if we've got some examples:
We can sequence them:
You could also require a
FutureSequenceinstance in your class's constructor, or on specific methods on your class.