What is going on in the match functionality? - scala

I have a method:
def replaceSpecialSymbols(str: String): String = str.collect {
case '/' => '-'
case _ => _
}.toString
Whe I try to build this code, I receive the error message: "error: unbound placeholder parameter case _ => _"
I know that I can use replaceAll. But I want to know what is going on in this case in Scala compiler.
Thank you.

Use case x => x — problem solved. Also, you can just use map instead of collect because it's an exhaustive match.
Or if you only need the first case, just remove that case _ => _ altogether and keep using collect.

Related

How to use a Result[String] in Scala match expression

In the following code the first expression returns a Result[String] which contains one of the strings "medical", "dental" or "pharmacy" inside of a Result. I can add .toOption.get to the end of the val statement to get the String, but is there a better way to use the Result? Without the .toOption.get, the code will not compile.
val service = element("h2").containingAnywhere("claim details").fullText()
service match {
case "medical" => extractMedicalClaim
case "dental" => extractDentalClaim
case "pharmacy" => extractPharmacyClaim
}
Hard to say without knowing what Result is. If it's a case class, with the target String as part of its constructor, then you could pattern match directly.
Something like this.
service match {
case Result("medical") => extractMedicalClaim
case Result("dental") => extractDentalClaim
case Result("pharmacy") => extractPharmacyClaim
case _ => // default result
}
If the Result class doesn't have an extractor (the upapply() method) you might be able to add one just for this purpose.
I'm assuming this Result[T] class has a toOption method which returns an Option[T] - if that's the case, you can call toOption and match on that option:
val service = element("h2").containingAnywhere("claim details").fullText().toOption
service match {
case Some("medical") => extractMedicalClaim
case Some("dental") => extractDentalClaim
case Some("pharmacy") => extractPharmacyClaim
case None => // handle the case where the result was empty
}

scala: convert match statement to pattern matching anonymous function - with values

like similar question: Convert match statement to partial function when foreach is used. Now similarly, IntelliJ asks me to improve my code. The difference is, that I use values for the matching:
val matchMe = "Foo"
keys.foreach(key =>
key match {
case `matchMe` => somethingSpecial()
case _ => somethingNormal(key, calcWith(key))
})
Refactoring this to a anonymous pattern-matching function would look something like:
keys.foreach {
case `matchMe` => somethingSpecial(_)
case _ => somethingNormal(_, calcWith(_)) //this doesn't work
}
Note that in the second case, I cannot use _ since I need it twice. Is there some way to use an anonymous pattern-matching function here?
You can't use the wildcard _ here, its purpose is to indicate you don't care about the value you're matching against.
You can use a named parameter :
keys.foreach {
case `matchMe` => somethingSpecial(matchMe)
case nonSpecialKey => somethingNormal(nonSpecialKey, calcWith(nonSpecialKey))
}
Without any restrictions placed on it, it will match any value. Do note that the order of cases is important, as case x => ... match anything and will essentially shortcut other case statements.
As an aside, I don't think your somethingSpecial(_) does what you want/expect it to. It's only a short version of x => somethingSpecial(x), not somethingSpecial(matchMe).

Scala type miss match

I am fairly new to scala and I am doing my assignment.
This is the code that I am using:
case EqNumC(l,r) => (interp(l),interp(r)) match{
case (NumV(s),NumV(x)) => if(s == x) BoolV(true) else BoolV(false)
case _ => throw InterpException("Value not found!")
}
When I run this code, it works fine and I get my result correctly. However this is somehow wrong. and I decided to make it better, by doing so:
case EqNumC(l,r) => (interp(l),interp(r)) match{
case (NumV(s),NumV(x)) => if(s==x) BoolV(true)
case (NumV(_),NumV(_)) => BoolV(false)
case _ => throw InterpException("Value not found!")
}
However When I run this I get this error:
Status: CompilationFailure
solution.scala:129: error: type mismatch;
found : Unit
required: Value
case (NumV(s),NumV(x)) => if(s==x) BoolV(true)
^
I don't see the problem here, because it's almost the same as the other one. How can I get rid of this problem and what is the best way to get this done?
The if control structure needs to come before the => when pattern-matching. When it comes after, the compiler sees an if without an else and infers it to be Unit (no return type).
It should look like this:
case (NumV(s),NumV(x)) if(s == x) => BoolV(true)
The first version works because if/else returns a value, but a single if does not.

Pattern matching using current object

I'm trying to match an Option, and test to see if it's a Some containing the object making the call. So the code I want to write looks like this:
methodReturningOption() match {
case Some(this) => doSomething()
case _ => doSomethingElse()
}
but that fails to compile, with the error
'.' expected but ')' found
I also tried using Some(`this`) which gives the error
not found: value this
I can make it work if I add a variable which refers to this
val This = this
methodReturningOption() match {
case Some(This) => doSomething()
case _ => doSomethingElse()
}
but that looks ugly and seems like an unpleasant workaround. Is there an easier way to pattern match with this as an argument?
I suppose you could try this:
methodReturningOption() match {
case Some(x) if x == this => doSomething()
case _ => doSomethingElse()
}
It looks like this is considered a special keyword and can't be used in that context.
Jack Leow's solution is probably the best - I'd recommend going with that since it's much more explicit. However as an alternative you can also create a variable point to 'this' using the following syntax. (Note the self => on the first line)
class Person { self =>
def bla() = methodReturningOption() match {
case Some(`self`) => ???
case _ => ???
}
}
This doesn't really answer the question, it's just a potential alternative syntax that may be useful to you.

Scala pattern matching case is skipped

Thanks for the excellent example, I tried it and it works as I expected. Nice to see someone understood the nature of the problem. However, I think I should have tagged the problem with Lift as I'm using the Lift framework and that is where this problem is (still) occurring (although I still think it might be related to extraction in scala). Since I don't want to reproduce the entire Lift setup here as it will be too much code, I'm going to hope someone familiar with Lift can understand what I'm doing here. I've removed more variables so it might be easier (for some) to see the problem:
lazy val dispatch: LiftRules.DispatchPF = {
// Explicitly setting guard to false to trigger the scenario
case req: Req if false => () => println("shouldn't match"); Empty
// This should match since previous case will never match
case Req(_, _, _) => () => println("should match"); Empty
// This is actually called...
case _ => () => println("shouldn't reach here"); Empty
}
As before, if I comment out the first case the second case is matched as expected.
For those interested, a simple workaround is:
lazy val dispatch: LiftRules.DispatchPF = {
case req: Req => {
if (false) { // Obviously you put something more useful than false here...
() => println("shouldn't match"); Empty
} else req match {
// This matches
case Req(_, _, _) => () => println("should match"); Empty
// This is now never called
case other => () => println("shouldn't reach here"); Empty
}
}
}
ORIGINAL POST
I'm new to scala, so I may be doing something wrong here, but I have a pattern matching expression that seems to be skipped over. Here's the code:
lazy val dispatch: LiftRules.DispatchPF = {
// Explicitly setting guard to false to trigger the scenario
case req: Req if false => () => Full(...)
// This should match since previous case will never match
case Req("api" :: "test" :: Nil, suffix, GetRequest) => () => Full(...)
// This is actually called...
case _ => () => println("not sure what's going on"); Empty
}
If I take out the first case expression, everything works as expected. I'm tempted to think this is a bug (https://issues.scala-lang.org/browse/SI-2337), but does anyone know of a workaround?
At the very least, change the last line:
case other => () => { println("not sure what's going on " + other); Empty }
and tell us what it prints
I just typed up an example which seems to be the same scenario you've got in your code, and it works as expected in Scala 2.9:
case class Foo(x:String)
val bar = Foo("bar")
bar match {
case x:Foo if false => println("Impossible")
case Foo(x) => println("Expected: " + x)
case _ => println("Should not happen")
}
Which outputs Expected: bar
See if you can reproduce the bug in a self-contained example like this, so maybe we (or if it is a bug, the Scala Dev Team, can figure out what is going wrong :)
Note: Seems like I misread your question the first time, sorry for that. I'm not going to delete this part anyway, because it might be helpful to someone else.
When using pattern matching, the first case-statement that matches will be executed, and after that, the match is complete and all other case statements will be ignored!
Your problem here is, that the first statement
case req:Req =>
matches every instance of Req. After matching the first statement and executing its code, Scala just jumps out of the match expression because it is finished. The second case-statement would match, but it is never executed for any given instance of Req because the first one matches. As far as I remember, this is known as shadowing a case statement.
So move your second case statement before the first one, and you should be fine.
Note that this is why in pattern matching, the more specific match cases need to come first and the more general case statements have to go last.
This is indeed the bug you are referencing in the Scala bug tracker. Req is a non-case class with a companion extractor methods, so the bug manifests itself here. The workaround you introduced seems fine.
For those interested, here is a sample case where the bug manifests itself:
class Sample(val a: String)
object Sample {
def apply(a: String) = new Sample(a)
def unapply(s: Sample) = Option(s.a)
}
val s = new Sample("a")
val r = s match {
case n: Sample if false => "Wrong 1: " + n
case Sample(_) => "Yay"
case n => "Wrong 2: " + n
}
println("Found " + r)
assert(r == "Yay")