Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Match a tuple of unknown size in scala

Is there way to partially match a tuple without having to specify the size? For example, if I had a tuple

val v = ( "Dr", "John","H", "Watson") 

I'd like to be able to do something like :

v match { 
   case ( "Dr", : _*) => "What's up, Doc?"
   case ( "Mr", name,   :_*) =>  s"Welcome, Mr. ${name}"
   case _ => "Have we met?"
} 

This doesn't compile, :_* normally means an undetermined number of parameters, but can't be used in this case apparently. The idea would be to be able to use this matcher for any tuple bigger than 2. I know i can do it converting v to a List (for example) first, just want to know if it's possible to do it with a tuple.

EDIT: the most information I found on the web is this discussion, which dates back to scala 2.8, so I'm gonna with the 'No, you can't' answer.

like image 300
Chirlo Avatar asked Mar 29 '13 23:03

Chirlo


People also ask

What is tuple2 in Scala?

In Scala, a tuple is a value that contains a fixed number of elements, each with its own type. Tuples are immutable. Tuples are especially handy for returning multiple values from a method. A tuple with two elements can be created as follows: Scala 2 and 3.

Does Scala have pattern matching?

Scala's pattern matching statement is most useful for matching on algebraic types expressed via case classes. Scala also allows the definition of patterns independently of case classes, using unapply methods in extractor objects.

What is match expression in Scala?

“match” is always defined in Scala's root class to make its availability to the all objects. This can contain a sequence of alternatives. Each alternative will start from case keyword. Each case statement includes a pattern and one or more expression which get evaluated if the specified pattern gets matched.

Can we have variables of different types inside of a tuple Scala?

Thankfully, Scala already has a built-in tuple type, which is an immutable data structure that we can use for holding up to 22 elements with different types.


2 Answers

Tuples are structures for heterogeneous types. As such, they implement the productIterator trait, so you could do:

v.productIterator.toList match { 
  case "Dr" :: _ => "What's up, Doc?"
  case "Mr" :: name :: _ =>  s"Welcome, Mr. ${name}"
  case _ => "Have we met?"
}

But your example really looks like you want a Seq[String] straight away. Is there any reason for wishing to use tuples?

like image 78
0__ Avatar answered Oct 10 '22 04:10

0__


This can be done using shapeless's conversions from tuples to HLists,

scala> import shapeless._
import shapeless._

scala> import Tuples._
import Tuples._

scala> val v = ( "Dr", "John","H", "Watson")
v: (String, String, String, String) = (Dr,John,H,Watson)

scala> v.hlisted match {
     |   case "Dr" :: _ => "What's up Doc?"
     |   case "Mr" :: name :: _ => s"Welcome, Mr. ${name}"
     |   case _ => "Have we met?"
     | }
res0: String = What's up Doc?

Although it's not visible in the above example, note that where possible full static type information is maintained for the names bound in the case clauses, for example,

scala> (23, "foo", true).hlisted match {
     |   case i :: s :: b :: HNil => if(b) i+s.length else 0
     |   case _ => -1
     | }
res1: Int = 26
like image 23
Miles Sabin Avatar answered Oct 10 '22 05:10

Miles Sabin