开发者

define a function with tuples

开发者 https://www.devze.com 2023-03-16 14:17 出处:网络
How can I define a function that is accepting all the tuples(1 to 22) as argument, I have something as follows in mind:

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 l开发者_运维技巧ength (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...


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.


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)


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


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


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)

  • http://jnordenberg.blogspot.com/2008/08/hlist-in-scala.html
  • a great and comprehensive series by Mark Harrah (of SBT fame)
  • Miles Sabin's github examples, taken from his recent talk at Scala eXchange


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

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号