3

How can I define a function that is accepting all the tuples(1 to 22) as argument, I have something as follows in mind:

def foo (v=Tuple) =...

foo((1,2))
foo((1,2,3))

EDIT:

To answer the comment: I am actually trying to create a Tensor class which is a set of values and a set of indices. The indices can be covariant and/or contravariant (cf Wikipedia1 and Wikipedia2). I wanted to have a special syntax like Tensor((1,2),(3,4),values) which would create a tensor with values, two covariant indices having length (2,3) and two contravariant indices with length (3,4). So using this syntax I could also write Tensor((1,2,3),3,values) (with an implicit Int=>Tuple1).

I agree that Tuples are not suitable for this, better to use Lists. However the syntax is not so nice then...

teucer
  • 6,060
  • 2
  • 26
  • 36
  • 3
    [Put down the chocolate-covered banana and step away from the European currency systems](http://homepage.ntlworld.com/jonathan.deboynepollard/FGA/put-down-the-chocolate-covered-banana.html): in order to provide meaningful help, we need to know more about your real problem. Why do you want to pass an arbitrary tuple in to your method? – Aaron Novstrup Jun 29 '11 at 03:01

6 Answers6

4

This really isn't what tuples are for (cf. the comments and answers here). Tuples are for doing things like returning multiple values from a method, where in Java you would have to create a lightweight class. If you have an arbitrary number of elements, you should use a collection.

Community
  • 1
  • 1
Rachel Shallit
  • 2,002
  • 14
  • 15
  • 1
    With the clarification, I'm not sure this answer really applies anymore. He's not trying to apply collection methods to tuples -- he really just wants to provide a convenient API for callers. – Aaron Novstrup Jun 29 '11 at 18:22
4

Another way to provide a convenient API to your users (aside from implicit conversion) is to use multiple parameter lists with varargs:

def tensor(cov: Int*)(contrav: Int*)(values: Int*) = // ...

Your examples would be written

tensor(1,2)(3,4)(values)
tensor(1,2,3)(3)(values)
Community
  • 1
  • 1
Aaron Novstrup
  • 20,967
  • 7
  • 70
  • 108
3

There is no trait specifically for tuples, but you could use a typeclass approach, as demonstrated in this answer.

If your goal is really to have a List but allow callers to pass in tuples (for convenience), you can modify that solution so that the type class produces a List rather than a Product.

In brief, the idea is that you provide implicit conversions from the types that callers can pass to the type you're actually going to use:

def foo(x: IndexList) = x.indices

sealed case class IndexList(indices: List[Int])

object IndexList {
   implicit def val2indices(i: Int) = IndexList(List(i))
   implicit def tuple2toIndices(t: (Int, Int)): IndexList = 
      product2indices(t)
   // etc
   implicit def list2indices(l: List[Int]) = IndexList(l)

   private def product2indices(p: Product) = 
      IndexList(p.productIterator.toList.asInstanceOf[List[Int]])
}

You can then call your method with any type for which you've provided a conversion:

foo(1)
foo((2,3))
foo(List(1,2,3))
Community
  • 1
  • 1
Aaron Novstrup
  • 20,967
  • 7
  • 70
  • 108
1

All case classes, including Tuples, extend scala.Product but unfortunately there's no marker trait specifically for tuples, so someone could sneak ordinary case classes into your method. Of course, there's no way to treat all arities in a uniform way and still be typesafe, but you can use productElement(n: Int) to extract the nth value, or productIterator to iterate over all the values.

But... This is heresy around here, but have you considered overloading? :)

Alex Cruise
  • 7,939
  • 1
  • 27
  • 40
1

What you probably want to use is an HList, not a tuple. An HList (heterogenous list) is basically an arbitrary-length, typed tuple.

There are a few examples of HLists in scala (they are not part of the standard library)

oxbow_lakes
  • 133,303
  • 56
  • 317
  • 449
0

Check this out. It actually works better than I expected ;)

scala> def f[T <: Product](x: T) = x
f: [T <: Product](x: T)T

scala> f(1)
<console>:9: error: inferred type arguments [Int] do not conform to method f's type parameter bounds [T <: Product]

scala> f(1, "2") // you don't even need the extra parenthesis
res0: (Int, java.lang.String) = (2,3)

scala> f(1, "2", BigInt("3"))
res1: (Int, java.lang.String, scala.math.BigInt) = (1,2,3)
agilesteel
  • 16,775
  • 6
  • 44
  • 55