I'm creating a macro that matches two expressions and an identifier. I would like to be able to ignore the identifier if it's not needed, but the compiler seems to complain if I use _ there.
My macro:
macro_rules! if_some {
($x:expr, $id:ident, $expr:expr) => {
match $x {
None => None,
Some($id) => Some($expr),
}
};
}
What I'd like to do:
if_some!(obtain_an_option(), x, do_something_with(x))
and
if_some!(obtain_an_option(), _, do_something())
The second call fails.
I worked around it by defining a second macro if_some_! that doesn't receive an identifier (I could not use a second pattern either). I'm sure there's a way to say "here accept an identifier or just _.
Maybe there's already a macro/function for this (like Option::map now I think about it)... nevertheless it'd be nice to now.
The simplest way is to add a second arm that matches an underscore:
macro_rules! if_some {
($x:expr, _, $expr:expr) => {
match $x {
None => None,
Some(_) => Some($expr),
}
};
($x:expr, $id:ident, $expr:expr) => {
match $x {
None => None,
Some($id) => Some($expr),
}
};
}
And, yes, this sounds like you just want Option::map.
Option::map seems to be the best solution for this particular problem, but when you really need a macro which expect both idents and _ as a pattern, you can also use the $p:pat fragment. The fragment of course accepts a broader range of patterns like (ref x, y), but typically this will be acceptable.
macro_rules! if_some {
($x:expr, $p:pat, $expr:expr) => {
match $x {
None => None,
Some($p) => Some($expr),
}
};
}
fn main() {
println!("{:?}", if_some!(Some(12), x, x + 1)); // Some(13)
println!("{:?}", if_some!(Some(12), _, 1)); // Some(1)
}
Related
I have to perform some actions based on cases in a pattern matching block, but only for selective cases, and nothing to be done for remaining. So is it ok to just return () for remaining cases? Something like this:
val x = ....
val y = ....
(x, y) match {
case (Some(number), Some(text)) => {
......
}
case (Some(number), None) => {
......
}
case (_, _) => () // do nothing
}
Depends what you mean by "ok". If you are asking if it will compile, you can easily answer that question yourself, by running a few snippets in a REPL and find out, that you don't even need to return a unit. Something like this works just fine:
"foo" match {
"bar" => "baz"
"bat" => 1500
_ =>
}
If however by "ok" you meant whether it is a good idea, then the answer is "probably not". As mentioned in the comments, this is not type-safe and also purely side-effecting and not referentially transparent. There is likely a better way to do what you want.
It's generally ok, if all the cases in a match result in Unit (spelled () in Scala), to have a case result in () to preserve exhaustivity.
That said, in this case, where you require the first Option to be defined to do anything, I would probably express this as:
x.foreach { number =>
y match {
case Some(text) =>
??? // note that { } aren't required in match and ??? is idiomatic for "some code here"
case None =>
???
}
}
Then again, I particularly dislike pattern matching on Option, so ymmv.
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.
How can I get the default value in match case?
//Just an example, this value is usually not known
val something: String = "value"
something match {
case "val" => "default"
case _ => smth(_) //need to reference the value here - doesn't work
}
UPDATE: I see that my issue was not really understood, which is why I'm showing an example which is closer to the real thing I'm working on:
val db = current.configuration.getList("instance").get.unwrapped()
.map(f => f.asInstanceOf[java.util.HashMap[String, String]].toMap)
.find(el => el("url").contains(referer))
.getOrElse(Map("config" -> ""))
.get("config").get match {
case "" => current.configuration.getString("database").getOrElse("defaultDatabase")
case _ => doSomethingWithDefault(_)
}
something match {
case "val" => "default"
case default => smth(default)
}
It is not a keyword, just an alias, so this will work as well:
something match {
case "val" => "default"
case everythingElse => smth(everythingElse)
}
The "_" in Scala is a love-and-hate syntax which could really useful and yet confusing.
In your example:
something match {
case "val" => "default"
case _ => smth(_) //need to reference the value here - doesn't work
}
the _ means, I don't care about the value, as well as the type, which means you can't reference to the identifier anymore.
Therefore, smth(_) would not have a proper reference.
The solution is that you can give the a name to the identifier like:
something match {
case "val" => "default"
case x => smth(x)
}
I believe this is a working syntax and x will match any value but not "val".
More speaking. I think you are confused with the usage of underscore in map, flatmap, for example.
val mylist = List(1, 2, 3)
mylist map { println(_) }
Where the underscore here is referencing to the iterable item in the collection.
Of course, this underscore could even be taken as:
mylist map { println }
here's another option:
something match {
case "val" => "default"
case default#_ => smth(default)
}
Given snippet composes of method calls, which return an option type. I'd like to call the next method if previous call returned None. I'm able to accomplish this with this snippet
def amountToPay : Option[TextBoxExtraction] =
getMaxByFontsize(keywordAmountsWithCurrency) match {
case None => getMaxByFontsize(keywordAmounts) match {
case None => highestKeywordAmount match {
case None => getMaxByFontsize(amountsWithCurrency) match {
case None => highestAmount
case some => some
}
case some => some
}
case some => some
}
case some => some
}
but it looks quite messy. So I hope there is abetter way to do it.
Yep, orElse is a little cleaner:
def amountToPay : Option[TextBoxExtraction] =
getMaxByFontsize(keywordAmountsWithCurrency)
.orElse(getMaxByFontsize(keywordAmounts))
.orElse(highestKeywordAmount)
.orElse(getMaxByFontsize(amountsWithCurrency))
.orElse(highestAmount)
You could also just put the items in a Seq and then use something like xs.reduceLeft(_ orElse _) or xs.flatten.headOption.getOrElse(highestAmount).
I have the following code in Play 2.0 template:
#content.toString.lines.map{
case line => // i put `case` here as another attempt to make it work
line match {
case "" => #Html("")
case _ => <li>#Html(line)</li> /*CRASH*/
}
}
It fails on the marked line, saying that not found: value line. The second variant of it:
#for(line <- content.toString.lines){
#line match { /*CRASH*/
case "" => #Html("")
case _ => <li>#Html(line)</li>
}
}
fails on the marked line, claiming that 'case' expected but identifier found.
UPDATE:
Same thing goes for val:
#val headID = "head"
comes up with illegal start of simple expression.
UPDATE ENDS
I would like to know, what am I doing wrong and how to correctly implement the match-case structure and val assignment in Play's templates?
Using match expressions in templates
You need to enclose in braces (“{” and “}”) the HTML content of your templates:
#for(line <- content.toString.lines) {
#line match {
case "" => { }
case _ => { <li>#Html(line)</li> }
}
}
In your specific case, the following code would read better IMHO:
#content.toString.lines.collect {
case line if !line.isEmpty => { <li>#Html(line)</li> }
}
Defining values
You can define values using the defining[T](value: T)(usage: T => Html) helper:
#defining(1 + 2 * 3) { value =>
<div>#value</div>
}
I found that add a {} outside to enclose entire code would work
#{content.toString.lines.map{ line =>
line match {
case "" => #Html("")
case _ => <li>#Html(line)</li>
}}
following seems to work for me
#content.toString.lines.map{ line =>
line match {
case "" => #Html("")
case _ => <li>#Html(line)</li>
}
hard on eyes, but you can look at target/scala-2.9.1/src_managed/main/views/html/index.template.scala in the play project directory to see what its putting in string literals.
As for val assignment, I don't know, but #defining may help
Another frequent cause of this error is to have the starting brace on a separate line:
#x match {
case y =>
{ //offending brace, put it back on the same line as case
} //This can go anywhere
}