Using comparison operators in Scala's pattern matching system
ScalaPattern MatchingScala Problem Overview
Is it possible to match on a comparison using the pattern matching system in Scala? For example:
a match {
case 10 => println("ten")
case _ > 10 => println("greater than ten")
case _ => println("less than ten")
}
The second case statement is illegal, but I would like to be able to specify "when a is greater than".
Scala Solutions
Solution 1 - Scala
You can add a guard, i.e. an if
and a boolean expression after the pattern:
a match {
case 10 => println("ten")
case x if x > 10 => println("greater than ten")
case _ => println("less than ten")
}
Edit: Note that this is more than superficially different to putting an if
after the =>
, because a pattern won't match if the guard is not true.
Solution 2 - Scala
As a non-answer to the question's spirit, which asked how to incorporate predicates into a match clause, in this case the predicate can be factored out before the match
:
def assess(n: Int) {
println(
n compare 10 match {
case 0 => "ten"
case 1 => "greater than ten"
case -1 => "less than ten"
})
}
Now, the documentation for scala.math.Ordering.compare(T, T)
promises only that the non-equal outcomes will be greater than or less than zero. Java's Comparable#compareTo(T)
is specified similarly to Scala's. It happens to be conventional to use 1 and -1 for the positive and negative values, respectively, as Scala's current implementation does, but one can't make such an assumption without some risk of the implementation changing out from underneath.
Solution 3 - Scala
A solution that in my opinion is much more readable than adding guards:
(n compare 10).signum match {
case -1 => "less than ten"
case 0 => "ten"
case 1 => "greater than ten"
}
Notes:
Ordered.compare
returns a negative integer if this is less than that, positive if greater, and0
if equal.Int.signum
compresses the output fromcompare
to-1
for a negative number (less than 10),1
for positive (greater than 10), or0
for zero (equal to 10).
Solution 4 - Scala
While all the above and bellow answers perfectly answer the original question, some additional information can be found in the documentation https://docs.scala-lang.org/tour/pattern-matching.html , they didn't fit in my case but because this stackoverflow answer is the first suggestion in Google I would like to post my answer which is a corner case of the question above.
My question is:
- How to use a guard in match expression with an argument of a function?
Which can be paraphrased:
- How to use an if statement in match expression with an argument of a function?
The answer is the code example below:
def drop[A](l: List[A], n: Int): List[A] = l match {
case Nil => sys.error("drop on empty list")
case xs if n <= 0 => xs
case _ :: xs => drop(xs, n-1)
}
link to scala fiddle : https://scalafiddle.io/sf/G37THif/2
as you can see the case xs if n <= 0 => xs
statement is able to use n(argument of a function) with the guard(if) statement.
I hope this helps someone like me.
Solution 5 - Scala
Scala's pattern matching allows you to define your own extractor. In this case, you can simply define a new extractor:
class GreaterThan(n: Int) {
def unapply(i: Int) = i > n
}
val GreaterThan10 = GreaterThan(10)
a match {
case 10 => ???
case GreaterThan10() => ???
case _ => ???
}
or just use pattern guards.