teucer
teucer

Reputation: 6238

define a function with tuples

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...

Upvotes: 3

Views: 3114

Answers (6)

Aaron Novstrup
Aaron Novstrup

Reputation: 21017

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)

Upvotes: 4

Aaron Novstrup
Aaron Novstrup

Reputation: 21017

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))

Upvotes: 3

oxbow_lakes
oxbow_lakes

Reputation: 134270

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)

Upvotes: 1

agilesteel
agilesteel

Reputation: 16859

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)

Upvotes: 0

Alex Cruise
Alex Cruise

Reputation: 7979

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? :)

Upvotes: 1

Rachel Shallit
Rachel Shallit

Reputation: 2010

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.

Upvotes: 4

Related Questions