Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

a clean way to combine two tuples into a new larger tuple in scala?

Tags:

scala

scalaz

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.

like image 731
jxstanford Avatar asked Jan 27 '12 03:01

jxstanford


2 Answers

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)
like image 175
huynhjl Avatar answered Oct 22 '22 04:10

huynhjl


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.

like image 35
Luigi Plinge Avatar answered Oct 22 '22 04:10

Luigi Plinge