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.
Related
This code compiles fine, but fails at runtime:
val values = Set("a").toSeq.sorted
values match {
case Nil => println("empty")
case h::t => println(s"h = $h")
}
With the error message:
scala.MatchError: ArrayBuffer(a) (of class scala.collection.mutable.ArrayBuffer)
I understand that somewhere in the process an ArrayBuffer is created, on which I cannot pattern-match like this. However, why can't the compiler tell me that this is not going to work?
You are matching on an open (extensible) data type, Scala's Seq. It could be a List, so Scala doesn't complain with your List pattern. On the other hand, exhaustiveness cannot be checked because it could really be any class implementing Seq (that we may not even know statically), so Scala just trusts you on this one.
You can use generic Seq patterns instead:
values match {
case Seq() => println("empty")
case h +: t => println(s"h = $h")
}
Or just convert to a List and use the same patterns (but Lists are not very efficient data structures, so it's probably better with the first option).
val values = Set("a").toList.sorted
values match {
case Nil => println("empty")
case h::t => println(s"h = $h")
}
Getting errors from pattern matching can be tricky sometimes, but in this case:
scala> :type values
Seq[String]
scala> Seq(1,2,3) match { case h::t => "ok" }
res1: String = ok
There's not enough type info to say it can't work, and it errs on the side of not annoying you.
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.
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.
I was experimenting with the following code;
(for (f <- (new File(".")).listFiles() if !f.isDirectory) yield f) match {
case x:File => println(x.getAbsoluteFile)
case _ => println(_)
}
Obviously I am wrong somehow, as I am getting the following Error
scrutinee is incompatible with pattern type;
found : java.io.File
required: Array[java.io.File]
case x:File => println(x.getAbsoluteFile)
^
What I was trying to do is pretty obvious; I tried to get each yielded value from the for-loop and pass it to a match-case "filter". I am not interesting in writing a better File tree filter rather than knowing the reason of the Error that I am getting and if it is possible to fix it (or rewrite somehow else).
Cheers!
Just a few symbols away:
for (f <- (new File(".")).listFiles() if !f.isDirectory) f match {
case x:File => println(x.getAbsoluteFile)
case _ => println(_)
}
The diff is
yield f)
{ f
In your case you're first processing (listing|filtering|yielding one-by-one) whole collection and only then match whole result.
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")