19

Let's say I have the following tuples:

scala> val t1 = Tuple2("abcd", "efg")
t1: (java.lang.String, java.lang.String) = (abcd,efg)

scala> val t2 = Tuple2(1234, "lmnop")
t2: (Int, java.lang.String) = (1234,lmnop)

scala> val t3 = Tuple3("qrs", "tuv", "wxyz")
t3: (java.lang.String, java.lang.String, java.lang.String) = (qrs,tuv,wxyz)

Is there a friendly way to combine them (in two steps if necessary) into a Tuple7? I'm really looking for a general answer for combining tuples of arbitrary size, and realize that there will be limitations due to the capped maximum tuple size. I am specifically looking for a tuple result, not a collection.

dhg
  • 52,383
  • 8
  • 123
  • 144
jxstanford
  • 3,339
  • 3
  • 27
  • 39
  • 2
    Check out HLists of various forms: https://github.com/harrah/up http://apocalisp.wordpress.com/2010/06/08/type-level-programming-in-scala/ http://stackoverflow.com/questions/8066654/covariance-in-type-level-programming/8067456#8067456 – Owen Jan 27 '12 at 05:34

2 Answers2

16

Shapeless requires dependent method types (-Ydependent-method-types) and I wish there was a downloadable binary for 2.9.1 so that I can simply try it out but it's really seems elegant. Based on this unit test it would apply to your case like this:

import shapeless.Tuples._
import shapeless.HList._
val t7 = (t1.hlisted ::: t2.hlisted ::: t3.hlisted).tupled

Although Miles indicates there is not guarantee of support, it actually has unit tests and the source is on github with an open source license so at least it's not just an experiment in a blog post.

Edit: works as advertized - took some time to compile and I had to add -Xss1m to sbt:

$ scala -Ydependent-method-types -cp target/scala-2.9.1/shapeless_2.9.1-1.1.0.jar
Welcome to Scala version 2.9.1.final (Java HotSpot(TM) Client VM, Java 1.7.0).
Type in expressions to have them evaluated.
Type :help for more information.

scala> import shapeless.Tuples._
import shapeless.Tuples._

scala> import shapeless.HList._
import shapeless.HList._

scala> val t1 = Tuple2("abcd", "efg")
t1: (java.lang.String, java.lang.String) = (abcd,efg)

scala> val t2 = Tuple2(1234, "lmnop")
t2: (Int, java.lang.String) = (1234,lmnop)

scala> val t3 = Tuple3("qrs", "tuv", "wxyz")
t3: (java.lang.String, java.lang.String, java.lang.String) = (qrs,tuv,wxyz)

scala> (t1.hlisted ::: t2.hlisted ::: t3.hlisted).tupled
res0: (java.lang.String, java.lang.String, Int, java.lang.String, java.lang.String,
java.lang.String, java.lang.String) = (abcd,efg,1234,lmnop,qrs,tuv,wxyz)
huynhjl
  • 41,520
  • 14
  • 105
  • 158
  • At some point I'll probably pimp the `HList`-style operations directly onto tuples, so you'll be able to skip the hlisted/tupled shuffle and just write `t1 ::: t2 ::: t3`. I've taken a pass at that on the [topic/tuples branch](https://github.com/milessabin/shapeless/tree/topic/tuples), but before I commit to it I want to be sure that the additional implicits don't cause havoc. – Miles Sabin Jan 27 '12 at 10:08
  • Yeah, this is exactly what I was looking for. Thanks huynhjl for pointing it out and the legwork to demonstrate that it satisfies the question, and thanks Miles for writing such a cool package! – jxstanford Jan 28 '12 at 06:33
  • Link to unit test does not exist anymore. What version of shapeless is this for? I cannot find `import shapeless.Tuples._` on version for scala 2.11 – Adrian Dec 04 '21 at 07:17
6

You really need to be using collections here, especially if all elements are the same type. You can combine tuples into a List without much difficulty:

def combine(xss: Product*) = xss.toList.flatten(_.productIterator)

Using your example:

scala> combine(t1, t2, t3)
res1: List[Any] = List(abcd, efg, hijk, lmnop, qrs, tuv, wxyz)

Trying to turn this back into tuples isn't going to work because your conversion method (e.g. with pattern matching) won't be able to return the specific tuple type (what's the return type of the method?), and the type information of each element has been lost.

Luigi Plinge
  • 50,650
  • 20
  • 113
  • 180
  • 4
    I should have given a better example. There is not guarantee that all members of the tuples will be of the same type, and I am specifically looking for a way to get the new tuple. Under other circumstances I would use a collection, but in this case the answer requires a tuple. I've refined the question... – jxstanford Jan 27 '12 at 05:28