I'm using shapeless in Scala, and I'd like to write a function allPairs that will take two HLists and return an HList of all pairs of elements. For example:
import shapeless._
val list1 = 1 :: "one" :: HNil
val list2 = 2 :: "two" :: HNil
// Has value (1, 2) :: (1, "two") :: ("one", 2) :: ("one", "two") :: HNil
val list3 = allPairs(list1, list2)
Any idea how to do this?
Also, I'd like to emphasize I'm looking for a function, not an inlined block of code.
You can't use a
for
-comprehension or a combination ofmap
andflatMap
with function literals here (as the other answers suggest), since these methods onHList
require higher rank functions. If you just have two statically typed lists, this is easy:Which gives us the following (appropriately typed):
Writing a method that will do this with
HList
arguments is trickier. Here's a quick example of how it can be done (with some slightly more general machinery).I'll start by noting that we can think of finding the Cartesian product of two ordinary lists as "lifting" a function that takes two arguments and returns them as a tuple into the applicative functor for lists. For example, you can write the following in Haskell:
We can write a polymorphic binary function that corresponds to
(,)
here:And define our example lists again for completeness:
Now we'll work toward a method named
liftA2
that will allow us to write the following:And get the correct result. The name
liftA2
is a little misleading, since we don't really have an applicative functor instance, and since it's not generic—I'm working on the model of the methods namedflatMap
andmap
onHList
, and am open to suggestions for something better.Now we need a type class that will allow us to take a
Poly2
, partially apply it to something, and map the resulting unary function over anHList
:And now a type class to help with the lifting:
And finally our method itself:
And that's all—now
liftA2(tuple)(xs, ys)
works.Just as we wanted.