Consider the following Scala code.
val a = "both"
a match {
case "both" | "foo" => println ("foo") // case 1
case "both" | "bar" => println ("bar") // case 2
}
I would like match to work so that if a == "both", Scala will execute both cases. Is this possible or are there any alternatives to achieve what I want?
Standard pattern-matching will always match on only exactly one case. You can get close to what you want by using the fact that patterns can be treated as partial functions (see the Language Specification, Section 8.5, Pattern Matching Anonymous Functions) and by defining your own matching operator, though:
class MatchAll[S](scrutinee : =>S) {
def matchAll[R](patterns : PartialFunction[S,R]*) : Seq[R] = {
val evald : S = scrutinee
patterns.flatMap(_.lift(evald))
}
}
implicit def anyToMatchAll[S](scrut : =>S) : MatchAll[S] = new MatchAll[S](scrut)
def testAll(x : Int) : Seq[String] = x matchAll (
{ case 2 => "two" },
{ case x if x % 2 == 0 => "even" },
{ case x if x % 2 == 1 => "neither" }
)
println(testAll(42).mkString(",")) // prints 'even'
println(testAll(2).mkString(",")) // prints 'two,even'
println(testAll(1).mkString(",")) // prints 'neither'
The syntax is slightly off the usual, but to me such a construction is still a witness to the power of Scala.
Your example is now written as:
// prints both 'foo' and 'bar'
"both" matchAll (
{ case "both" | "foo" => println("foo") },
{ case "both" | "bar" => println("bar") }
)
(Edit huynhjl pointed out that he gave a frighteningly similar answer to this question.)
At risk of being Captain Obvious, in a case like this it would be simplest just to forget pattern matching and use if.
if (a == "both" || a == "foo") println("foo")
if (a == "both" || a == "bar") println("bar")
If the repetition of a == worries you, you could instead write
if (Set("both", "foo")(a)) println("foo")
if (Set("both", "bar")(a)) println("bar")
using the fact that the apply method on Set does the same as contains, and is a bit shorter.
match executes one, and only one, of the cases, so you can't do this as an or in the match. You can, however, use a list and map/foreach:
val a = "both"
(a match {
case "both" => List("foo", "bar")
case x => List(x)
}) foreach(_ match {
case "foo" => println("foo")
case "bar" => println("bar")
})
And you're not duplicating any of the important code (in this case the printlns).
Just match twice:
val a = "both"
a match {
case "both" | "foo" => println ("foo") // Case 1
}
a match {
case "both" | "bar" => println ("bar") // Case 2
}
One possible way could be:
val a = "both"
a match {
case "foo" => println ("foo") // Case 1
case "bar" => println ("bar") // Case 2
case "both" => println ("foo"); println ("bar")
}
Related
Let's suppose I have a class Toto with two optional fields :
case class Toto(a : Option[Int], b: Option[Int])
And a class Titi with one optional Toto :
case class Titi(c : Option[Toto])
We create an instance of a class Titi :
val test = Titi(Some(Toto(Some(1),Some(2))))
Now I want to access the second field of Toto in Titi variable by supposing that Titi or b can be equal to None but this statement is impossible :
test.c.getOrElse("Something").b.getOrElse(0)
How do I proceed to do so ?
You should use flatMap:
test.c.flatMap(_.b).getOrElse(0)
In a case in any place in the hierarchy there is None 0 will be returned.
If you have even a deeper object hierarchy with properties returning Option you can chain flatMap:
test.c
.flatMap(_.b)
.flatMap(_.d)
//...etc
Scala also has also the special syntax for unwrapping deeply nested monadic types, called for comprehension:
val result = for {
c <- test.c
a <- c.a
} yield a
result.getOrElse(0)
Under the hood, it is compiled to similar code as chained flatMap.
This basically works like this:
If c is None to gets directly to getOrElse and returns 0
If it's Some then it checks b, if it's None it goes to getOrElse if not then value wrapped in Some is returned.
In case you would want to return something different distinguishing which Option is None, then I would just use match:
test.c match {
case Some(c) => c.getOrElse(0)
// if you return String in one branch and integer in other then inferred type would be Any!
case None => "Something"
}
Your val test is wrong, it should be this
val test = Titi(Some(Toto(Some(1),Some(2))))
Other thing, in the getOrElse, you have to put a type that makes sense
test.c.getOrElse(Toto(None,None))
you can achieve it by pattern matching
val test: Titi = Titi(Some(Toto(Some(1), None)))
val res = test.c match {
case Some(Toto(_, Some(x))) => x
case _ => 0
}
result:
0
val x = test match {
case Titi(x) => {
x match {
case Some(x) => {
x.b match {
case Some(z) => z
case None => 1
}
}
case None => 1
}
}
case _ => 1
} //> x : Int = 2
u can use fold
test.c.fold(0)(_.b.fold(0)(i => i))
I want to pattern match using the same "case" to 2 different case classes but I am getting an error that the binded variable name is already in use:
for instance this:
statement match {
case FirstCase(a,b) => {lots of logic using "a" and "b"}
case SecondCase( obj : FirstCase, somethingElse) => {same logic as above}
...
...
}
I'd love to re-use the same logic :
statement match {
case obj: FirstCase | SecondCase( obj : FirstCase, somethingElse) =>
{lots of logic using "obj.a" and "obj.b"}
...
...
}
But I am getting a compile error "obj is already defined in scope"
Is it possible to "re-use" the name of the binded object?
You can use helper method:
def hlp(a: TypeOfA, b: TypeOfB) = ???
statement match {
case FirstCase(a, b) => hlp(a, b)
case SecondCase(FirstCase(a, b), somethingElse) => hlp(a, b)
}
A couple of alternatives to the other answer:
You can use intermediate variables:
val (a,b) = statement match {
case FirstCase(a,b) => a -> b
case SecondCase(FirstCase(a,b), somethingElse) => a -> b
}
// Use a and b
You can create an extractor object
object AB {
def unapply(x: Any) = x match {
case FirstCase(a,b) => Some(a -> b)
case SecondCase(FirstCase(a,b), somethingElse) => Some(a -> b)
}
}
statement match {
case AB(a,b) => // use a and b here (you don't need the braces btw
}
I have a match statement like this:
val x = y match {
case array: Array[Float] => call z
case array: Array[Double] => call z
case array: Array[BigDecimal] => call z
case array: Array[_] => show error
}
How do I simplify this to use only two case statements, since first three case statements do same thing, instead of four.
Type erasure does not really gives you opportunity to understand how array was typed. What you should do instead is to extract head ( first element) of array and check it's type. For example following code works for me:
List(1,2,3) match {
case (a:Int) :: tail => println("yep")
}
This work, although not very nice:
def x(y: Array[_]) = y match {
case a if a.isInstanceOf[Array[Double]] ||
a.isInstanceOf[Array[Float]] ||
a.isInstanceOf[Array[BigDecimal]] => "call z"
case _ => "show error"
}
Would have thought that pattern matching with "|" as below would do the trick. However, this gives pattern type is incompatible with expected type on Array[Float] and Array[BigDecimal]. It might be that matching of generic on this single case where it could work has not been given so much attention:
def x(y: Array[_ <: Any]) = y match {
case a # (_:Array[Double] | _:Array[Float] | _:Array[BigDecimal]) => "call z"
case a: Array[_] => "show error"
}
May be it helps a bit:
import reflect.runtime.universe._
object Tester {
def test[T: TypeTag](y: Array[T]) = y match {
case c: Array[_] if typeOf[T] <:< typeOf[AnyVal] => "hi"
case c: Array[_] => "oh"
}
}
scala> Tester.test(Array(1,2,3))
res0: String = hi
scala> Tester.test(Array(1.0,2.0,3.0))
res1: String = hi
scala> Tester.test(Array("a", "b", "c"))
res2: String = oh
You can obtain the class of array elements as follows (it will be null for non-array types): c.getClass.getComponentType. So you can write:
if (Set(classOf[Float], classOf[Double], classOf[BigDecimal]).contains(c.getClass.getComponentType)) {
// call z
} else {
// show error
}
Not particularly Scala'ish, though; I think #thoredge's answer is the best for that.
You could also check whether the Array is empty first and then if not, just pattern match on Array.head...something like:
def x(y: Array[_]) = {
y.isEmpty match {
case true => "error"
case false => y.head match {
case a:Double | a:BigInt => do whatever
case _ => "error"
}
}
}
This question already has answers here:
Pattern Match "return" value
(2 answers)
Closed 9 years ago.
Chaining match expressions does not compile.
val x = Array("abc", "pqr")
x match {
case Array("abc", _*) => Some("abc is first")
case Array("xyz", _*) => Some("xyz is first")
case _ => None
} match {
case Some(x) => x
case _ => "Either empty or incorrect first entry"
}
While the following compiles fine:
(x match {
case Array("abc", _*) => Some("abc is first")
case Array("xyz", _*) => Some("xyz is first")
case _ => None
}) match {
case Some(x) => x
case _ => "Either empty or incorrect first entry"
}
Why does the later version (where first match expression is in paranthesis) compile fine while earlier one does not?
If it were allowed, you couldn't do:
scala> List(1,2,3) last match { case 3 => true }
warning: there were 1 feature warning(s); re-run with -feature for details
res6: Boolean = true
That is, if it were infix notation, then the thing to the left could not be postfix.
Disallowing infix match permits a postfix scrutinee.
That expression is parsed the natural way
(List(1,2,3) last) match { case 3 => true }
that is, if postfix notation is natural and not unholy.
The feature warning is for import language.postfixOps. Perhaps with that feature turned off, the Defenders of the Good would be willing to entertain import language.infixMatch.
Consider constructs that are syntactic siblings to match, that are not infixable without parens:
scala> if (true) 1 else 2 match { case 1 => false }
res4: AnyVal = 1 // not false
scala> (if (true) 1 else 2) match { case 1 => false }
res1: Boolean = false
or
scala> throw new IllegalStateException match { case e => "ok" }
<console>:11: error: type mismatch; // not "ok", or rather, Nothing
found : String("ok")
required: Throwable
throw new IllegalStateException match { case e => "ok" }
^
scala> (throw new IllegalStateException) match { case e => "ok" }
java.lang.IllegalStateException
I'm often writing code that compares two objects and produces a value based on whether they are the same, or different, based on how they are different.
So I might write:
val result = (v1,v2) match {
case (Some(value1), Some(value2)) => "a"
case (Some(value), None)) => "b"
case (None, Some(value)) => "b"
case _ = > "c"
}
Those 2nd and 3rd cases are the same really, so I tried writing:
val result = (v1,v2) match {
case (Some(value1), Some(value2)) => "a"
case (Some(value), None)) || (None, Some(value)) => "b"
case _ = > "c"
}
But no luck.
I encounter this problem in a few places, and this is just a specific example, the more general pattern is I have two things, and I want to know if one and only one of them meet some predicate, so I'd like to write something like this:
val result = (v1,v2) match {
case (Some(value1), Some(value2)) => "a"
case OneAndOnlyOne(value, v: Option[Foo] => v.isDefined ) => "b"
case _ = > "c"
}
So the idea here is that OneAndOnlyOne can be configured with a predicated (isDefined in this case) and you can use it in multiple places.
The above doesn't work at all, since its backwards, the predicate needs to be passed into the extractor not returned.
How about something like this?
val result = (v1,v2) match {
case (Some(value1), Some(value2)) => "a"
case new OneAndOnlyOne(v: Option[Foo] => v.isDefined )(value) => "b"
case _ = > "c"
}
with:
class OneAndOnlyOne[T](predicate: T => Boolean) {
def unapply( pair: Pair[T,T] ): Option[T] = {
val (item1,item2) = pair
val v1 = predicate(item1)
val v2 = predicate(item2)
if ( v1 != v2 )
Some( if ( v1 ) item1 else item2 )
else
None
}
}
But, this doesn't compile.
Can anyone see a way to make this solution work? Or propose another solution? I'm probably making this more complicated than it is :)
I think you're asking two slightly different questions.
One question is how to use "or" in switch statements. || doesn't work; | does. And you can't use variables in that case (because in general they might match different types, which renders the type confusing). So:
def matcher[T](a: (T,T)) = {
a match {
case (Some(x),Some(y)) => "both"
case (Some(_),None) | (None,Some(_)) => "either"
case _ => "none"
}
}
Another question is how to avoid having to do this over and over, especially if you want to be able to get at the value in the tuple. I've implemented a version here for Option, but you could use an unwrapped tuple and a boolean.
One trick to achieve this is that to prewrap the values before you start matching on it, and then use your own matching constructs that do what you want. For instance,
class DiOption[+T] {
def trinary = this
}
case class Both[T](first: T, second:T) extends DiOption[T] { }
case class OneOf[T](it: T) extends DiOption[T] { }
case class Neither() extends DiOption[Nothing] { }
implicit def sometuple2dioption[T](t2: (Option[T],Option[T])): DiOption[T] = {
t2 match {
case (Some(x),Some(y)) => Both(x,y)
case (Some(x),None) => OneOf(x)
case (None,Some(y)) => OneOf(y)
case _ => Neither()
}
}
// Example usage
val a = (Some("This"),None)
a trinary match {
case Both(s,t) => "Both"
case OneOf(s) => "Just one"
case _ => "Nothing"
}
If you have to support arbitrary predicates you can derive from this (which is based on Daniel's idea):
List(v1, v2) filter (_ %2 == 0) match {
case List(value1, value2) => "a"
case List(value) => "b"
case _ => "c"
}
the definition of the function:
def filteredMatch[T,R](values : T*)(f : T => Boolean)(p: PartialFunction[List[T], R]) : R =
p(List((values filter f) :_* ))
Now you can use it like this:
filteredMatch(v1,v2)(_ %2 == 0){
case List(value1, value2) => "a"
case List(value) => "b"
case _ => "c"
}
I'm not so sure if it's a good idea (i.e. readable). But a neat exercise nonetheless.
It would be nice if you could match on tuples: case (value1, value2) => ... instead of lists.
How about this:
Welcome to Scala version 2.8.0.r20327-b20091230020149 (Java HotSpot(TM) Client VM, Java 1.6.0_17).
Type in expressions to have them evaluated.
Type :help for more information.
scala> def m(v1: Any,v2: Any) = (v1,v2) match {
| case (Some(x),Some(y)) => "a"
| case (Some(_),None) | (None,Some(_)) => "b"
| case _ => "c"
| }
m: (v1: Any,v2: Any)java.lang.String
scala> m(Some(1),Some(2))
res0: java.lang.String = a
scala> m(Some(1),None)
res1: java.lang.String = b
scala> m(None,None)
res2: java.lang.String = c
scala>
You should be able to do it if you define it as a val first:
val MyValThatIsCapitalized = new OneAndOnlyOne(v: Option[Foo] => v.isDefined )
val result = (v1,v2) match {
case (Some(value1), Some(value2)) => "a"
case MyValThatIsCapitalized(value) => "b"
case _ = > "c"
}
As implied by the name, the name of the val containing the extractor object must be capitalized.
On Scala 2.8:
val result = List(v1,v2).flatten match {
case List(value1, value2) => "a"
case List(value) => "b"
case _ = > "c"
}
On Scala 2.7, however, you need a type hint to make it work. So, assuming value is Int, for instance, then:
val result = (List(v1,v2).flatten : List[Int]) match {
case List(value1, value2) => "a"
case List(value) => "b"
case _ = > "c"
}
The funny thing about it is that I misread "first" as "list" on Mitch Blevins answer, and that gave me this idea. :-)
Since you already matched against (Some(x), Some(y)), you may match against (None, None) explicitly, and the remaining cases are (Some(x), None) and (None, Some(y)):
def decide [T](v1: Option[T], v2:Option[T]) = (v1, v2) match {
case (Some (x), Some (y)) => "a"
case (None, None) => "c"
case _ => "b"
}
val ni : Option [Int] = None
decide (ni, ni) // c
decide (Some (4), Some(3)) // a
decide (ni, Some (3)) // b
decide (Some (4), ni) // b