1

Is there a succinct way to check if an expression matches a given pattern? For instance, consider the following code:

val result = expr match {
    SomePattern(_, 1, _) => true
    _ => false
}

While this code works, it is fairly noise and long. I was wondering if there is a nicer way to achieve the same. It would be great if Scala had a matches construct, that would allow one to write

val result = expr matches SomePattern(_, 1, _)

I would even consider writing a helper function to make something along those lines possible. However, that seems difficult to do, because I cannot pass a pattern as an argument as far as I know. Maybe something like this would be possible with macros that are available in Scala 2.10 (as experimental feature)?

stefan
  • 1,135
  • 1
  • 11
  • 22
  • ooo, yes, Paul Phillips' answer to the linked question is probably the best you'll get :) –  Feb 01 '13 at 15:09

3 Answers3

2
scala> import PartialFunction.cond
import PartialFunction.cond

scala> cond(Option(2)) { case Some(2) => true }
res0: Boolean = true

scala> cond(Option(3)) { case Some(2) => true }
res1: Boolean = false

That said, I supported "matches" in the past, though there are plenty methods called that.

Daniel C. Sobral
  • 295,120
  • 86
  • 501
  • 681
  • This is certainly good that it is in the standard library. However, typing is somewhat restrictive, as the following won't compile: `cond(None){ case Some(_) => true }`. It fails with `constructor cannot be instantiated to expected type. found : Some[A], required: None.type`. – Régis Jean-Gilles Feb 01 '13 at 15:43
  • that is why "some" and "none" should be methods (as in Scalaz, iirc) –  Feb 01 '13 at 15:47
  • @RégisJean-Gilles but this will: `cond(None: Option[_]){ case Some(_) => true }`. Just saying it is not too restrictive, given that most of the time (I actually can't think about other cases) you want to match against value that has option type. – om-nom-nom Feb 01 '13 at 15:51
  • @asfierl: No, `cond` could simply just be typed differently. By example defining it as `def cond(x: Any)(pf: PartialFunction[Any, Boolean])= ...` fixed the problem. Though I guess you can argue that now the typing is too general and could fail to catch some logic errors. @om-nom-nom: sure, but it feels needlessly verbose. – Régis Jean-Gilles Feb 01 '13 at 15:52
  • 1
    @Daniel I would rename it to matches: `import PartialFunction.{cond => matches}` because cond is somewhat odd name for the most of programmers, imo. – om-nom-nom Feb 01 '13 at 15:56
  • I second that. Unfortunately, being in the standard library this can't be renamed without breaking backward compatibility. – Régis Jean-Gilles Feb 01 '13 at 16:17
  • @RégisJean-Gilles What on-nom-nom suggested is to rename it on *import*, which is perfectly possible. – Daniel C. Sobral Feb 02 '13 at 02:29
  • Doh, I did not actually read the code snippet, sorry for that. – Régis Jean-Gilles Feb 02 '13 at 09:14
1

You could define a function "matches" that does something like that, e.g.:

scala> def matches[A](a: A)(f: PartialFunction[A, Unit]) = f isDefinedAt a
matches: [A](a: A)(f: PartialFunction[A,Unit])Boolean

scala> matches("abc") { case "abc" => () }
res0: Boolean = true

scala> matches("abc") { case "x" => () }
res1: Boolean = false
0

The exact same syntax allowed by the match construct can be used to write PartialFunctions as function literals. But the compiler has to know that's what's required. In other words, it needs something to drive type inference:

scala> val pf1 = { case i: Int if i % 2 == 0 => true; case i: Int => false }
<console>:42: error: missing parameter type for expanded function
The argument types of an anonymous function must be fully known. (SLS 8.5)
Expected type was: ?
       val pf1 = { case i: Int if i % 2 == 0 => true; case i: Int => false }
                 ^

scala> val pf2: Function[Int, Boolean] = { case i: Int if i % 2 == 0 => true; case _ => false }
<console>:42: error: $r.intp.global.Function does not take type parameters
       val pf2: Function[Int, Boolean] = { case i: Int if i % 2 == 0 => true; case _=> false }
                ^
<console>:42: error: missing parameter type for expanded function
The argument types of an anonymous function must be fully known. (SLS 8.5)
Expected type was: <error>
       val pf2: Function[Int, Boolean] = { case i: Int if i % 2 == 0 => true; case _=> false }
                                         ^

scala> val pf3: PartialFunction[Int, Boolean] = { case i: Int if i % 2 == 0 => true; case _ => false }
pf3: PartialFunction[Int,Boolean] = <function1>
Randall Schulz
  • 26,420
  • 4
  • 61
  • 81