I'm trying to construct multiple cross products of traversables of different (but each homogeneous) types. The desired return type is a traversable of a tuple with the type matching the types in the input traversables. For example:
List(1, 2, 3) cross Seq("a", "b") cross Set(0.5, 7.3)
This should give a Traversable[(Int, String, Double)]
with all possible combinations from the three sources. The case of combining only two sources was nicely answered here. The given idea is:
implicit class Crossable[X](xs: Traversable[X]) {
def cross[A](ys: Traversable[A]) = for { x <- xs; y <- ys } yield (x, y)
}
The comments there briefly mention the problem of more sources, but I'm looking to find a solution that does not depend on either shapeless or scalaz (on the other hand, I don't mind having some boilerplate to scale up to Tuple22
). What I would like to do is something like the following:
implicit class Crossable[X](xs: Traversable[X]) {
def cross[A](ys: Traversable[A]) = for { x <- xs; y <- ys } yield (x, y)
def cross[A,B](ys: Traversable[(A,B)]) = // ... extend all Tuple2's in ys with x in xs to Tuple3's
def cross[A,B,C](ys: Traversable[(A,B,C)]) = // ...
// ...
}
This obviously does not work due to type erasure (and, unfortunately, would probably require to use parenthesis in the example above, because cross
would be right associative).
My question is: Is it somehow possible to exploit Scala 2.10's reflection features to solve the problem? In general, matching both A
and X
to the various tuple types (and their type parameters, which seems challenging) and merging them to larger tuples should provide a solution satisfying the associative law, right?