I have an Option of String which may be empty too. I have written following code to handle different branches of flow:
input match {
case Some(val) => {
val match {
case "sayHi" => "Hi"
case "sayHello" => "Hello"
case _ => extractFromAnotherInput
}
}
None => extractFromAnotherInput
}
private def extractFromAnotherInput = {
anotherInput match {
case a => ....
case b => ....
}
}
Is this a good way of handling code branches in a functional language or it can be done in a better way?
You don't have to nest the matches:
input match {
case Some("sayHi") => "Hi"
case Some("sayHello") => "Hello"
case _ => extractFromAnotherInput
}
You can also combine this input with "another", and "strip" he option before doing the match:
input.getOrElse(anotherInput) match {
case "sayHi" => "Hi"
case "sayHello" => "Hello"
case a => ...
case b => ...
}
I would go with Dima's solution. Or if you want to use some method on Option:
input.collect{
case "sayHi" => "Hi"
case "sayHello" => "Hello"
}
.getOrElse(extractAnotherInput)
Just because, I would like to propose an alternative to Levi's answer; just to remark this is more of a matter of opinion.
input.filter(_.nonEmpty).fold(ifEmpty = extractAnotherInput) {
case "sayHi" => "Hi"
case "sayHello" => "Hello"
}
This is a matter of style: I personally dislike pattern-matching on Option, but that's idiosyncratic (I also may be the only Scala programmer who generally dislikes the for notation, but that's neither here nor there).
I'd express that as
input.flatMap { v =>
v match {
case "sayHi" => Some("Hi")
case "sayHello" => Some("Hello")
case _ => None
}
}.getOrElse(extractAnotherInput)
If overfitting to this example (exploiting the fact that I can uniformly transform sayHi and sayHello)
input.filter(v => v == "sayHi" || v == "sayHello")
.map(_.drop(3))
.getOrElse(extractAnotherInput)
Related
What is the higher order function equivalent expression to the following?
def isRepeated:Boolean = {
prev match {
case Some(a) => a.prev match {
case Some(b) => b.equals(this)
case None => false
}
case None => false
}
}
I believe this is equivalent:
def isRepeated:Boolean = prev.exists(_.prev.exists(_.equals(this)))
Say I have the following
case class IntWrap(value:Int)
I would like to extract the same variable from two cases as follows:
x match {
case value:Int | IntWrap(value) => dosomethingwith(x)
case _ => ???
}
but the only way I have been able to do this is as:
x match {
case value:Int => dosomethingwith(x)
case IntWrap(value) => dosomethingwith(x)
case _ => ???
}
Is there a better way, as in my real life case dosomething is actually a large block of code which is not so easy to encapsulate.
If it is really the case that you want to do something with x, not with the extracted value, then the following would work:
case class IntWrap(value:Int) // extends T
def dosomethingwith(x: Any) = x
val x: Any = IntWrap(101)
x match {
case _: Int | _: IntWrap => dosomethingwith(x)
case _ => ???
}
If you actually want to work with the extracted value, you could factor out the corresponding match block into its own extractor and reuse that wherever necessary:
x match {
case Unwrap(value) => dosomethingwith(value)
case _ => ???
}
object Unwrap {
def unapply(x: Any) = x match {
case x: Int => Some((x))
case IntWrap(value) => Some((value))
case _ => None
}
}
I honestly don't see an issue with the way you are doing things. As long as dosomethingwith is a separate function then I don't see any issues with duplicate code. If your code looked like this then I don't see any need to come up with other solutions:
def foo(x:Any){
x match {
case value:Int => dosomethingwith(value)
case IntWrap(value) => dosomethingwith(value)
case _ => ???
}
}
def dosomethingwith(x:Int){
//do something complicated here...
}
I came up with sth a little bit different, but it may help you avoid duplicates:
case class IntWrap(value: Int)
implicit def intWrapToInt(intWrap: IntWrap) = intWrap.value
def matchInt(x: AnyVal) = x match {
case i: Int => println("int or intWrap")
case _ => println("other")
}
//test
matchInt(IntWrap(12)) //prints int or intWrap
matchInt(12) //prints int or intWrap
matchInt("abc") //prints other
It won't work for every reference, though. So, be careful.
I oftentimes face the following problem:
val b = a match {
case Some(a) => "1"
case None => "n"
}
val c = a match {
case Some(a) => "2"
case None => "n"
}
Obviously, the match is executed twice even though it is only necessary once. How can I make sure the compiler takes this into account?
I don't think there will be any performance gain but you can write your code like this:
val (b, c) = a match {
case Some(a) => ("1","2)
case None => ("n", "n")
}
Matches can be extremely fast--comparable to an if-statement. Don't worry about doing the work twice unless it's a difficult match.
It's slightly easier to match a default than another case, so if you really don't need the parameter your best bet is
val b = a match { case None => "n"; case _ => "1" }
val c = a match { case None => "n"; case _ => "2" }
This will often even outperform a mutable solution like
var b,c = "n"
a match { case Some(_) => b = "1"; c = "2"; case _ => }
and will certainly outperform any tuple-creation.
If the match is a time-consuming one then you have to store your results and return them in a tuple or other suitable data structure, as om-nom-nom has already demonstrated. This may also be more clear, depending on context.
Is there an easy/best way to get a BitSet I can pattern match like a list?
val btst = BitSet(1,2,3,4)
btst match {
...
case head :: tail => tail
}
By definition a set is an unordered collection, and pattern matching over such one is error-prone. Convert it to list if you want to... Also, you should not rely on head and tail to always return the same thing.
A BitSet is ordered, but extractorless.
Edit: but not humorless.
object |<| {
def unapply(s: BitSet): Option[(Int, BitSet)] =
if (s.isEmpty) None
else Some((s.head, s.tail))
}
def flags(b: BitSet) = b match {
case f"5 || 10" => println("Five and dime") // alas, never a literal
case 5 |<| any => println(s"Low bit is 5iver, rest are $any")
case i |<| any => println(s"Low bit is $i, rest are $any")
case _ => println("None")
}
def dump(b: BitSet) = println(b.toBitMask.mkString(","))
val s = BitSet(5, 7, 11, 17, 19, 65)
dump(s)
// ordinary laborious tests
s match {
case x if x == BitSet(5) => println("Five")
case x if x == BitSet(5,7,11,17,19,65) => println("All")
case x if x(5) => println("Five or more")
case _ => println("None")
}
// manually matching on the mask is laborious
// and depends on the bit length
s.toBitMask match {
case Array(2L) => println("One")
case Array(657568L) => println("First word's worth")
case Array(657568L, _) => println("All")
case _ => println("None")
}
// or truncate for special case
s.toBitMask(0) match {
case 2L => println("One")
case 657568L => println("First word's worth")
case _ => println("None")
}
How does one combine (in a nice way) two Scala match'es?
First I have to test if an Option is a valid value:
myOption match {
case Some(op) =>
doSomethingWith(op)
case None =>
handleTheError()
Then if op was valid, I want to test for another pattern:
Path(request.path) match {
case "work" => {
println("--Let's work--")
}
case "holiday" => {
println("--Let's relax--")
}
case _ => {
println("--Let's drink--")
}
}
I could combine them like this:
myOption match {
case Some(op) =>
doSomethingWith(op)
Path(request.path) match {
case "work" => {
println("--Let's work--")
}
case "holiday" => {
println("--Let's relax--")
}
case _ => {
println("--Let's drink--")
}
}
case None =>
handleTheError()
But, it feels sloppy. Is there a better way to combine them in some way or another.
Update
Apologies, I should have explained better. I'm actually trying to find out if there is a known pattern for simplifying (or factoring out) these control structures. For example (imagine this was true):
x match {
case a => {
y match {
case c => {}
case d => {}
}
}
case b => {}
}
equals
x -> y match {
case a -> c => {}
case a -> d => {}
case b => {}
}
I was just wandering if someone has already identified some refactoring patterns for control flow, much like algebra where 2(x + y) = 2x + 2y
You can do
myOption map { success } getOrElse handleTheError
or with scalaz,
myOption.cata(success, handleTheError)
where success is something like
def success(op: Whatever) = {
doSomethingWith(op)
Path(request.path) match {
case "work" => println("--Let's work--")
case "holiday" => println("--Let's relax--")
case _ => println("--Let's drink--")
}
}
Update
Your pseudocode
x -> y match {
case a -> c => {}
case a -> d => {}
case b => {}
}
can be literally translated to scala as
(x, y) match {
case (a, c) => {}
case (a, d) => {}
case (b, _) => {}
}
It looks nice (and that's probably what you wanted) if inner matcher have only few options (c and d in this case), but it leads to code duplication (repeating of pattern a). So, in general I'd prefer map {} getOrElse {}, or separation of pattern-matchers on smaller functions. But I repeat, in your case it looks reasonable.
If the scrutinees (the expressions on which you match) do not depend on each other, i.e. you can compute them independently, you could perform both matches at the same time by wrapping the scrutinees in a tuple.
So your example:
x match {
case a => {
y match {
case c => fooC(...)
case d => fooD(...)
}
}
case b => fooB(...)
}
could be rewritten as:
(x,y) match {
case (a, c) => fooC(...)
case (a, d) => fooD(...)
case (b, _) => fooB(...)
}
...as long as y doesn't depend on x.