Why isn't it possible to place expressions in case statements? :
x match {
case <VALUE EXPR> => {}
}
For example
x match {
case (1+2) => {}
}
is not allowed, but
val someval = (1+new java.util.Random().nextInt())
x match {
case someval => {}
}
is. It seems that if the second case is allowed, so should the first.
I'm trying to add a list of mappings like this:
val typ:Type = symbol.typeSignature
typ match {
case typeOf[collection.immutable.List[Any]] => { return a function to handle this type }
case typeOf[...] => {}
case typeOf[...] => {}
... many
}
It simply defies the definition of patterns in pattern matching.
From the Scala Language Specification, chapter 8:
A pattern is built from constants, constructors, variables and type tests
"Expressions" is not in this list, and that makes some sense - think about it - when will this expression be evaluated? What if it has side-effects, will it be evaluated even if a case preceding it was used to return the result?
A valid workaround is using a guard, which is evaluated:
x match {
case i if i == (1+2) => {} // works as expected...
}
Related
I have a method that receives a function, but that function may be partial, in such case I don't want it to fail with MatchError.
def doSomething[X,Y](opt:Option[X])(f:X=>Y)={
f match {
case p:PartialFunction[X,Y]=> opt.flatMap(p.lift) //This doesn't seem to work
case _ => opt.map(f)
}
}
That way I can use the method like this
doSomething(x){
case t if predicate(t) => otherMethod(t)
}
so in case I don't have a predicate, I can use it like
this doSomething(x)(otherMethod) instead of
doSoemthing(x){
case t=> otherMethod(t)
}
Note: Looking for a solution that doesn't require catching MatchError exceptions
This isn't an answer because I don't think that what you want is possible in Scala.
The original method is fine and works as expected, though it could be a bit simpler:
def doSomething[X, Y](opt: Option[X])(f: X => Y): Option[Y] = {
f match {
case p: PartialFunction[X, Y] => opt.collect(p)
case _ => opt.map(f)
}
}
The problem is here:
doSomething(x){
case t if predicate(t) => otherMethod(t)
}
Scala is creating a Function rather than a PartialFunction from that match expression so the test is failing. If you pass a real PartialFunction the method works OK.
val p: PartialFunction[Int, Int] = {
case i: Int if i > 0 => i
}
doSomething(Some(0))(p) // Returns None
I don't think there is any way of doing what you want, mainly because doSomething has multiple argument lists which messes up type deduction for the second argument list.
My suggestion is just to use
x.map(f)
or
x.collect{
case ...
}
as appropriate in the calling code.
The syntax for partial function has been changed since 2.9 per SLS 8.5, so that even you do { case x => y}, it DOES NOT mean it is a partial function. Its type will be exact as you define it as.
In your case, you defined it as X=>Y (as in your function parameter), so it is just a X=>Y (it got compiled into a regular function, and non match cases will throw MatchError), and even you do isInstanceOf[PartialFunciton[_,_]], it won't match.
To make your scenario work, you can just simply cast the passed function as PartialFunction, like:
doSomething(Some(1))({case 2 => 0}: PartialFunction[Int,Int]) //This returns None without MatchError
while
doSomething(Some(1)){case 2 => 0} //This gives MatchError and it is not recognized as PartialFunction inside the body
This is probably not as convenient as you thought it is, but it is the only way to make it work. (or you define 2 separate functions for either case, like collect and map in standard library)
I'm not sure what you are passing as a Partial Function, but definitely you should have to define it with specific signature like this:
val positive: PartialFunction[Int, Option[Int]] = {
case x if x >= 0 => Some(x)
case _ => None
The positive function is defined only for positive numbers. In case of negative numbers, the function returns None and you won't get scala.MatchError in runtime.
This specific function enables you to access to isDefinedAt method which is testing dynamically if a value is in the domain of the function.
postive(5).isDefinedAt // true
poistive.isInstanceOf[PartialFunction[Int, Option[Int]]] // true
I demonstrated here why you are always getting false when you check p.isInstanceOf
def doSomething[X,Y](opt:Option[X])(f:X=>Y)={
f match {
case p if p.isInstanceOf[PartialFunction[X,Y]] =>
println("I'm a pf")
println(s"Is it PartialFunction: ${p.isInstanceOf[PartialFunction[X,Y]]}")
opt.map(p)
case _ =>
println("I'm not a pf")
opt.map(f)
}
}
doSomething[Int, Option[Int]](Some(5))(positive) // partial function case
doSomething[Int, String](Some(5)) { // tricky case
case s => s.toString
}
You can play with it here:
I have been working with Scala for close to a year, but every now and then I come across a piece of code that I don't really understand. This time it is this one. I tried looking into documents on "scala methods with generic parameter type", but I am still confused.
def defaultCall[T](featureName : String) (block : => Option[T])(implicit name: String, list:Seq[String]) : Option[T] =
{
val value = block match {
case Some(n) => n match {
case i : Integer => /*-------Call another method----*/
case s : String => /*--------Call another method----*/
}
case _ => None
}
The method is called using the code shown below :
var exValue = Some(10)
val intialization = defaultCall[Integer]("StringName"){exValue}
What I don't understand in the above described code is the "case" statement in the defaultCall method.
I see that when the exValue has a value and is not empty, the code works as expected. But in case I change the exValue to None, then my code goes into the "case _ = None" condition. I don't understand why this happens since the match done here is against the "variable" which would be either an Integer or a String.
What happens here is that when you pass a None it will match on the second case, which "catches" everything that is not an instance of a Some[T]:
block match {
case Some(n) => // Will match when you pass an instance of Some[T]
case _ => // Will match on any other case
}
Note that None and Some are two different classes that inherit from Option.
Also, the variable match is only done if the first match succeeds, otherwise not. To achieve the type checking in the first match you could do:
block match {
case Some(n: Int) => // do stuff
case Some(n: String) => // do stuff
case _ => // Will match on any other case
}
Hope that helps
I found myself writing something like this quite often:
a match {
case `b` => // do stuff
case _ => // do nothing
}
Is there a shorter way to check if some value matches a pattern? I mean, in this case I could just write if (a == b) // do stuff, but what if the pattern is more complex? Like when matching against a list or any pattern of arbitrary complexity. I'd like to be able to write something like this:
if (a matches b) // do stuff
I'm relatively new to Scala, so please pardon, if I'm missing something big :)
This is exactly why I wrote these functions, which are apparently impressively obscure since nobody has mentioned them.
scala> import PartialFunction._
import PartialFunction._
scala> cond("abc") { case "def" => true }
res0: Boolean = false
scala> condOpt("abc") { case x if x.length == 3 => x + x }
res1: Option[java.lang.String] = Some(abcabc)
scala> condOpt("abc") { case x if x.length == 4 => x + x }
res2: Option[java.lang.String] = None
The match operator in Scala is most powerful when used in functional style. This means, rather than "doing something" in the case statements, you would return a useful value. Here is an example for an imperative style:
var value:Int = 23
val command:String = ... // we get this from somewhere
command match {
case "duplicate" => value = value * 2
case "negate" => value = -value
case "increment" => value = value + 1
// etc.
case _ => // do nothing
}
println("Result: " + value)
It is very understandable that the "do nothing" above hurts a little, because it seems superflous. However, this is due to the fact that the above is written in imperative style. While constructs like these may sometimes be necessary, in many cases you can refactor your code to functional style:
val value:Int = 23
val command:String = ... // we get this from somewhere
val result:Int = command match {
case "duplicate" => value * 2
case "negate" => -value
case "increment" => value + 1
// etc.
case _ => value
}
println("Result: " + result)
In this case, you use the whole match statement as a value that you can, for example, assign to a variable. And it is also much more obvious that the match statement must return a value in any case; if the last case would be missing, the compiler could not just make something up.
It is a question of taste, but some developers consider this style to be more transparent and easier to handle in more real-world examples. I would bet that the inventors of the Scala programming language had a more functional use in mind for match, and indeed the if statement makes more sense if you only need to decide whether or not a certain action needs to be taken. (On the other hand, you can also use if in the functional way, because it also has a return value...)
This might help:
class Matches(m: Any) {
def matches[R](f: PartialFunction[Any, R]) { if (f.isDefinedAt(m)) f(m) }
}
implicit def any2matches(m: Any) = new Matches(m)
scala> 'c' matches { case x: Int => println("Int") }
scala> 2 matches { case x: Int => println("Int") }
Int
Now, some explanation on the general nature of the problem.
Where may a match happen?
There are three places where pattern matching might happen: val, case and for. The rules for them are:
// throws an exception if it fails
val pattern = value
// filters for pattern, but pattern cannot be "identifier: Type",
// though that can be replaced by "id1 # (id2: Type)" for the same effect
for (pattern <- object providing map/flatMap/filter/withFilter/foreach) ...
// throws an exception if none of the cases match
value match { case ... => ... }
There is, however, another situation where case might appear, which is function and partial function literals. For example:
val f: Any => Unit = { case i: Int => println(i) }
val pf: PartialFunction[Any, Unit] = { case i: Int => println(i) }
Both functions and partial functions will throw an exception if called with an argument that doesn't match any of the case statements. However, partial functions also provide a method called isDefinedAt which can test whether a match can be made or not, as well as a method called lift, which will turn a PartialFunction[T, R] into a Function[T, Option[R]], which means non-matching values will result in None instead of throwing an exception.
What is a match?
A match is a combination of many different tests:
// assign anything to x
case x
// only accepts values of type X
case x: X
// only accepts values matches by pattern
case x # pattern
// only accepts a value equal to the value X (upper case here makes a difference)
case X
// only accepts a value equal to the value of x
case `x`
// only accept a tuple of the same arity
case (x, y, ..., z)
// only accepts if extractor(value) returns true of Some(Seq()) (some empty sequence)
case extractor()
// only accepts if extractor(value) returns Some something
case extractor(x)
// only accepts if extractor(value) returns Some Seq or Tuple of the same arity
case extractor(x, y, ..., z)
// only accepts if extractor(value) returns Some Tuple2 or Some Seq with arity 2
case x extractor y
// accepts if any of the patterns is accepted (patterns may not contain assignable identifiers)
case x | y | ... | z
Now, extractors are the methods unapply or unapplySeq, the first returning Boolean or Option[T], and the second returning Option[Seq[T]], where None means no match is made, and Some(result) will try to match result as described above.
So there are all kinds of syntactic alternatives here, which just aren't possible without the use of one of the three constructions where pattern matches may happen. You may able to emulate some of the features, like value equality and extractors, but not all of them.
Patterns can also be used in for expressions. Your code sample
a match {
case b => // do stuff
case _ => // do nothing
}
can then be expressed as
for(b <- Some(a)) //do stuff
The trick is to wrap a to make it a valid enumerator. E.g. List(a) would also work, but I think Some(a) is closest to your intended meaning.
The best I can come up with is this:
def matches[A](a:A)(f:PartialFunction[A, Unit]) = f.isDefinedAt(a)
if (matches(a){case ... =>}) {
//do stuff
}
This won't win you any style points though.
Kim's answer can be “improved” to better match your requirement:
class AnyWrapper[A](wrapped: A) {
def matches(f: PartialFunction[A, Unit]) = f.isDefinedAt(wrapped)
}
implicit def any2wrapper[A](wrapped: A) = new AnyWrapper(wrapped)
then:
val a = "a" :: Nil
if (a matches { case "a" :: Nil => }) {
println("match")
}
I wouldn't do it, however. The => }) { sequence is really ugly here, and the whole code looks much less clear than a normal match. Plus, you get the compile-time overhead of looking up the implicit conversion, and the run-time overhead of wrapping the match in a PartialFunction (not counting the conflicts you could get with other, already defined matches methods, like the one in String).
To look a little bit better (and be less verbose), you could add this def to AnyWrapper:
def ifMatch(f: PartialFunction[A, Unit]): Unit = if (f.isDefinedAt(wrapped)) f(wrapped)
and use it like this:
a ifMatch { case "a" :: Nil => println("match") }
which saves you your case _ => line, but requires double braces if you want a block instead of a single statement... Not so nice.
Note that this construct is not really in the spirit of functional programming, as it can only be used to execute something that has side effects. We can't easily use it to return a value (therefore the Unit return value), as the function is partial — we'd need a default value, or we could return an Option instance. But here again, we would probably unwrap it with a match, so we'd gain nothing.
Frankly, you're better off getting used to seeing and using those match frequently, and moving away from this kind of imperative-style constructs (following Madoc's nice explanation).
This code is from Querying a Dataset with Scala's Pattern Matching:
object & { def unapply[A](a: A) = Some((a, a)) }
"Julie" match {
case Brothers(_) & Sisters(_) => "Julie has both brother(s) and sister(s)"
case Siblings(_) => "Julie's siblings are all the same sex"
case _ => "Julie has no siblings"
}
// => "Julie has both brother(s) and sister(s)"
How does & actually work? I don't see a Boolean test anywhere for the conjunction. How does this Scala magic work?
Here's how unapply works in general:
When you do
obj match {case Pattern(foo, bar) => ... }
Pattern.unapply(obj) is called. This can either return None in which case the pattern match is a failure, or Some(x,y) in which case foo and bar are bound to x and y.
If instead of Pattern(foo, bar) you did Pattern(OtherPattern, YetAnotherPatter) then x would be matched against the pattern OtherPattern and y would be matched against YetAnotherPattern. If all of those pattern matches are successful, the body of the match executes, otherwise the next pattern is tried.
when the name of a pattern is not alphanumeric, but a symbol (like &), it is used infix, i.e. you write foo & bar instead of &(foo, bar).
So here & is a pattern that always returns Some(a,a) no matter what a is. So & always matches and binds the matched object to its two operands. In code that means that
obj match {case x & y => ...}
will always match and both x and y will have the same value as obj.
In the example above this is used to apply two different patterns to the same object.
I.e. when you do
obj match { case SomePattern & SomeOtherPattern => ...}`
first the pattern & is applied. As I said, it always matches and binds obj to its LHS and its RHS. So then SomePattern is applied to &'s LHS (which is the same as obj) and SomeOtherPattern is applied to &'s RHS (which is also the same as obj).
So in effect, you just applied two patterns to the same object.
Let's do this from the code. First, a small rewrite:
object & { def unapply[A](a: A) = Some(a, a) }
"Julie" match {
// case Brothers(_) & Sisters(_) => "Julie has both brother(s) and sister(s)"
case &(Brothers(_), Sisters(_)) => "Julie has both brother(s) and sister(s)"
case Siblings(_) => "Julie's siblings are all the same sex"
case _ => "Julie has no siblings"
}
The new rewrite means exactly the same thing. The comment line is using infix notation for extractors, and the second is using normal notation. They both translate to the same thing.
So, Scala will feed "Julie" to the extractor, repeatedly, until all unbound variables got assigned to Some thing. The first extractor is &, so we get this:
&.unapply("Julie") == Some(("Julie", "Julie"))
We got Some back, so we can proceed with the match. Now we have a tuple of two elements, and we have two extractors inside & as well, so we feed each element of the tuple to each extractor:
Brothers.unapply("Julie") == ?
Sisters.unapply("Julie") == ?
If both of these return Some thing, then the match is succesful. Just for fun, let's rewrite this code without pattern matching:
val pattern = "Julie"
val extractor1 = &.unapply(pattern)
if (extractor1.nonEmpty && extractor1.get.isInstanceOf[Tuple2]) {
val extractor11 = Brothers.unapply(extractor1.get._1)
val extractor12 = Sisters.unapply(extractor1.get._2)
if (extractor11.nonEmpty && extractor12.nonEmpty) {
"Julie has both brother(s) and sister(s)"
} else {
"Test Siblings and default case, but I'll skip it here to avoid repetition"
}
} else {
val extractor2 = Siblings.unapply(pattern)
if (extractor2.nonEmpty) {
"Julie's siblings are all the same sex"
} else {
"Julie has no siblings"
}
Ugly looking code, even without optimizing to only get extractor12 if extractor11 isn't empty, and without the code repetition that should have gone where there's a comment. So I'll write it in yet another style:
val pattern = "Julie"
& unapply pattern filter (_.isInstanceOf[Tuple2]) flatMap { pattern1 =>
Brothers unapply pattern1._1 flatMap { _ =>
Sisters unapply pattern1._2 flatMap { _ =>
"Julie has both brother(s) and sister(s)"
}
}
} getOrElse {
Siblings unapply pattern map { _ =>
"Julie's siblings are all the same sex"
} getOrElse {
"Julie has no siblings"
}
}
The pattern of flatMap/map at the beginning suggests yet another way of writing this:
val pattern = "Julie"
(
for {
pattern1 <- & unapply pattern
if pattern1.isInstanceOf[Tuple2]
_ <- Brothers unapply pattern1._1
_ <- Sisters unapply pattern1._2
} yield "Julie has both brother(s) and sister(s)
) getOrElse (
for {
_ <- Siblings unapply pattern
} yield "Julie's siblings are all the same sex"
) getOrElse (
"julie has no siblings"
)
You should be able to run all this code and see the results for yourself.
For additional info, I recommend reading the Infix Operation Patterns section (8.1.10) of the Scala Language Specification.
An infix operation pattern p op q is a
shorthand for the constructor or
extractor pattern op(p,q). The
precedence and associativity of
operators in patterns is the same as
in expressions.
Which is pretty much all there is to it, but then you can read about constructor and extractor patterns and patterns in general. It helps separate the syntactic sugar aspect (the "magic" part of it) from the fairly simple idea of pattern matching:
A pattern is built from constants,
constructors, variables and type
tests. Pattern matching tests whether
a given value (or sequence of values)
has the shape defined by a pattern,
and, if it does, binds the variables
in the pattern to the corresponding
components of the value (or sequence
of values).
regarding the following scala code, functions m2a and m2b apparently differ only by the case of the parameter, ie abc vs Abc. This seems to make some difference in the result as per example below. When running it with a recent 2.8 compiler, it results in the following (I would have expected all true). Any insights would be appreciated.
m1=true
m2a=true
m2b=false
m3=true
code
package sample
import scala.xml._
object ParamTest extends Application {
def m1(n:Node, abc:String):Boolean = {
n == <id>{Text(abc)}</id>
}
def m2a(n:Node, Abc:String):Boolean = n match {
case <id>{Text(Abc)}</id> => true
case _ => false;
}
// why does this one not work?
def m2b(n:Node, abc:String):Boolean = n match {
case <id>{Text(abc)}</id> => true
case _ => false;
}
def m3(n:Node, abc:String):Boolean = n match {
case Elem(_,"id",_,_, c #_ *) => {
c contains Text(abc)
}
}
def runner(n:Node, f:(Node, String)=>Boolean):Boolean = {
f(n, "x") && !f(n, "y") && !f(n, "");
}
val x = <id>x</id>
println("m1="+runner(x, m1));
println("m2a="+runner(x, m2a));
println("m2b="+runner(x, m2b));
println("m3="+runner(x, m3));
}
The trick here is in how Scala handles variables in case expressions. Lowercase variables in case expressions are taken by the compiler to introduce new variables, which are then pattern matched against. Thus in method m2b, the method parameter "abc" is actually unused. The case expression variable "abc" will match any string, since it is not otherwise constrained. Thus "y" is successfully matched in the first case of m2b. Uppercase variables in case expressions do not introduce new variables, so in m2a the match behaves as you expected.
The easiest way to match against the value of a lowercase variable is to wrap it in backquotes. Thus
def m2b(n:Node, abc:String):Boolean = n match {
case <id>{Text(`abc`)}</id> => true
case _ => false;
}
will give you the results you expected.
In pattern matching, identifiers in the pattern that start with a lower-case letter are taken to be free pattern variables that can be bound to values in the target of the match. Those that start with upper-case letters are so-called stable identifiers and must already be bound in the match expression's context and the value of that binding must equal the subexpression of the match target at the point in that value corresponding to that stable identifier's placement within the pattern expression.
Additionally, and relevant in this particular example, pattern variables (the lower-case names) will shadow any existing binding of the same name that is in effect in the context of the match expression (including the expression supplying the match target value).