I have an scenario where I need to call up to three services to do something. Each service has some kind of priority and my algorithm depends on the combination of the result of each service (all of them, two or even one). In order to handle this situation I want to use pattern matching (because the matchs, and variable extraction)
Here you are a simplified example.
case class Foo(bar: String, baz: Option[String])
def expensiveOperation1(): String = ???
def expensiveOperation2(): List[Int] = ???
def expensiveOperation3(): Foo = ???
lazy val r1 = expensiveOperation1()
lazy val r2 = expensiveOperation2()
lazy val r3 = expensiveOperation3()
(r1, r2, r3) match {
case ("Value1", _, _) => "1"
case ("Value2", _, _) => "2"
case (_, List(1), _) => "3"
case (_, Nil, _) => "4"
case ("Value3", 1 :: tail, _) => "5" + tail
case (_, _, Foo("x", Some(x))) => x
case (_, _, _) => "7"
}
As you can see, there is no need to call expensiveOperation2 and expensiveOperation3 all the time, but though I save each result on lazy vals, in the moment when I create Tuple3, each method is called.
I could create a container LazyTuple3 with three params call by name in order to solve that problem, but I'll get a new problem, unapply method (LazyTuple3.unapply) returns an Option, so after the first "case" each method will be called.
I could solve this with nested "if" or "match" but I want to give a chance with one "match", I find it clearer.
Any idea?
Thanks in advance.
Try to use scalaz.Need. https://static.javadoc.io/org.scalaz/scalaz_2.12/7.2.26/scalaz/Need.html
case class Foo(bar: String, baz: Option[String])
def expensiveOperation1(): String = {
println("operation1")
"Value3"
}
def expensiveOperation2(): List[Int] = {
println("operation2")
List(1, 2, 3)
}
def expensiveOperation3(): Foo = {
println("operation3")
Foo("x", Some("x"))
}
lazy val r1 = Need(expensiveOperation1())
lazy val r2 = Need(expensiveOperation2())
lazy val r3 = Need(expensiveOperation3())
(r1, r2, r3) match {
case (Need("Value1"), _, _) => "1"
case (Need("Value2"), _, _) => "2"
case (_, Need(List(1)), _) => "3"
case (_, Need(Nil), _) => "4"
case (Need("Value3"), Need(1 :: tail), _) => "5" + tail
case (_, _, Need(Foo("x", Some(x)))) => x
case (_, _, _) => "7"
}
This will print:
operation1
operation2
Related
I have the following code snapshot with repeatable boilerplate with profusion of underscore:
...............
case (a, c) =>
(a, c.map {
case (_, aParam, _, _, _, _, _, _, _, _, _) => aParam
},
c.map {
case (_, _ , cParam, _, _, _, _, _, _, _, _) => cParam
},
c.map {
case (_, _ , dParam, _, _, _, _, _, _, _, _) => dParam
}
................
c.map {
case (_, _ , _, _, _, _, _, _, _, _, eParam) => eParam
}
I would like to replace this boilerplate, but i wouldn't like to use shapeless or another library.
UPD
c has type List[(Int, String, ......, String)]
case (a, c) =>
(a, c.map(_._2).map {
case aParam => aParam
}, c.map(_._3).map {
case cParam => cParam
}, c.map(_._2).map {
case dParam => dParam
}, ..., c.map(_._11).map {
case eParam => eParam
})
This does exactly the same as your code, although I'm not sure about what aParam, cParam and others exactly are.
You could clean your code a little with the following:
case (a, c) =>
c.map{
case (c1, c2, c3, c4, c5, c6, c7, c8, c9, c10, c11) =>
// do whatever processing you like here for each value in the tuple above
c2.filter(_.equals(aParam)).doStuff
...
}
You may want something like this:
//########################################################
//Old Way (If i understand ur approach correctly)
val tup1 = (7, "apple", "ball", "Cat", "dog")
val tup2 = (8, "w", "x", "y", "z")
val tup3 = (9, "r1", "r2", "r3", "r4")
var tupList: List[(Int, String, String, String, String)] = List(tup1, tup2, tup3)
tupList.foreach(item => {
item match {
case (_, "apple", _, _, _) => println("apple")
case (_, _, "x", _, _) => println("y")
case (_, _, _, _, "r4") => println("r4")
}
})
//#######################################################
//New Way ~
//Define your match filter like this: (key - position(0 based index)), ("apple", 1) ~ case (_, "apple", _, _, _)
val filter: List[(String, Int)] = List(("apple", 1), ("x", 2), ("r4", 4))
//Now, iterate through list, convert each tuple to iterator, and check each item of tuple with
//filter condition, i.e. item must match filter string and index e.g. ("apple", 1)
//Also, you don't have to worry about size of list or tuple. You can create some generic method as well using this logic.
tupList.map(tup => {
val iterator = tup.productIterator
var i = 0
while (iterator.hasNext) {
val item = iterator.next()
filter.map(f => {
val filterString = f._1
val position = f._2
if (i == position && item == filterString) {
println(tup) //matched.
}
})
i = i + 1
}
})
Let a class
case class C(val i: Int) {
var assignee: Option[String] = None
}
and for a given assignment to a variable named x,
val x = C(1)
x: C = C(1)
how to get value "x": String to x.assignee, namely
assert( x.assignee == Some("x") )
Local variable names aren't available at runtime. But you can capture it with a macro at compile-time. See e.g. definingValName at https://github.com/sbt/sbt/blob/9c442d3aed53bdc89db1ada9d5b204bf02adb339/main/settings/src/main/scala/sbt/std/KeyMacro.scala and its usages:
def definingValName(c: Context, invalidEnclosingTree: String => String): String = {
import c.universe.{ Apply => ApplyTree, _ }
val methodName = c.macroApplication.symbol.name
def processName(n: Name): String = n.decoded.trim // trim is not strictly correct, but macros don't expose the API necessary
def enclosingVal(trees: List[c.Tree]): String = {
trees match {
case vd # ValDef(_, name, _, _) :: ts => processName(name)
case (_: ApplyTree | _: Select | _: TypeApply) :: xs => enclosingVal(xs)
// lazy val x: X = <methodName> has this form for some reason (only when the explicit type is present, though)
case Block(_, _) :: DefDef(mods, name, _, _, _, _) :: xs if mods.hasFlag(Flag.LAZY) => processName(name)
case _ =>
c.error(c.enclosingPosition, invalidEnclosingTree(methodName.decoded))
"<error>"
}
}
enclosingVal(enclosingTrees(c).toList)
}
def enclosingTrees(c: Context): Seq[c.Tree] =
c.asInstanceOf[reflect.macros.runtime.Context].callsiteTyper.context.enclosingContextChain.map(_.tree.asInstanceOf[c.Tree])
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")
}
If I'm doing lots of pattern matching against a (relatively) complex case class, but most of the time I'm only interested in one or two of its fields. Is there a way to abstract away the other fields (perhaps by wrapping the class?)? Here's an example of the type of thing I'm trying to simplify:
def receive = {
case HttpRequest(POST, "foo", _, HttpBody(_, body), _) => // action
case HttpRequest(GET, "bar", _, _, _) => // action
}
I'm only ever really interested in the request type, url and sometimes body so I would ideally like to define a pattern match as case Request(POST, "foo", body) or similar.
Just make your own Request extractor. Here's a simplified example:
case class Complex(a: String, b: Int, c: String)
object Simple {
def unapply(c: Complex): Option[(String, Int)] = Some(c.a, c.b)
}
Complex("B", 2, "x") match {
case Simple("A", i) => println("found A, " + i)
case Simple("B", i) => println("found B, " + i)
}
// prints "found B, 2"
I'm often writing code that compares two objects and produces a value based on whether they are the same, or different, based on how they are different.
So I might write:
val result = (v1,v2) match {
case (Some(value1), Some(value2)) => "a"
case (Some(value), None)) => "b"
case (None, Some(value)) => "b"
case _ = > "c"
}
Those 2nd and 3rd cases are the same really, so I tried writing:
val result = (v1,v2) match {
case (Some(value1), Some(value2)) => "a"
case (Some(value), None)) || (None, Some(value)) => "b"
case _ = > "c"
}
But no luck.
I encounter this problem in a few places, and this is just a specific example, the more general pattern is I have two things, and I want to know if one and only one of them meet some predicate, so I'd like to write something like this:
val result = (v1,v2) match {
case (Some(value1), Some(value2)) => "a"
case OneAndOnlyOne(value, v: Option[Foo] => v.isDefined ) => "b"
case _ = > "c"
}
So the idea here is that OneAndOnlyOne can be configured with a predicated (isDefined in this case) and you can use it in multiple places.
The above doesn't work at all, since its backwards, the predicate needs to be passed into the extractor not returned.
How about something like this?
val result = (v1,v2) match {
case (Some(value1), Some(value2)) => "a"
case new OneAndOnlyOne(v: Option[Foo] => v.isDefined )(value) => "b"
case _ = > "c"
}
with:
class OneAndOnlyOne[T](predicate: T => Boolean) {
def unapply( pair: Pair[T,T] ): Option[T] = {
val (item1,item2) = pair
val v1 = predicate(item1)
val v2 = predicate(item2)
if ( v1 != v2 )
Some( if ( v1 ) item1 else item2 )
else
None
}
}
But, this doesn't compile.
Can anyone see a way to make this solution work? Or propose another solution? I'm probably making this more complicated than it is :)
I think you're asking two slightly different questions.
One question is how to use "or" in switch statements. || doesn't work; | does. And you can't use variables in that case (because in general they might match different types, which renders the type confusing). So:
def matcher[T](a: (T,T)) = {
a match {
case (Some(x),Some(y)) => "both"
case (Some(_),None) | (None,Some(_)) => "either"
case _ => "none"
}
}
Another question is how to avoid having to do this over and over, especially if you want to be able to get at the value in the tuple. I've implemented a version here for Option, but you could use an unwrapped tuple and a boolean.
One trick to achieve this is that to prewrap the values before you start matching on it, and then use your own matching constructs that do what you want. For instance,
class DiOption[+T] {
def trinary = this
}
case class Both[T](first: T, second:T) extends DiOption[T] { }
case class OneOf[T](it: T) extends DiOption[T] { }
case class Neither() extends DiOption[Nothing] { }
implicit def sometuple2dioption[T](t2: (Option[T],Option[T])): DiOption[T] = {
t2 match {
case (Some(x),Some(y)) => Both(x,y)
case (Some(x),None) => OneOf(x)
case (None,Some(y)) => OneOf(y)
case _ => Neither()
}
}
// Example usage
val a = (Some("This"),None)
a trinary match {
case Both(s,t) => "Both"
case OneOf(s) => "Just one"
case _ => "Nothing"
}
If you have to support arbitrary predicates you can derive from this (which is based on Daniel's idea):
List(v1, v2) filter (_ %2 == 0) match {
case List(value1, value2) => "a"
case List(value) => "b"
case _ => "c"
}
the definition of the function:
def filteredMatch[T,R](values : T*)(f : T => Boolean)(p: PartialFunction[List[T], R]) : R =
p(List((values filter f) :_* ))
Now you can use it like this:
filteredMatch(v1,v2)(_ %2 == 0){
case List(value1, value2) => "a"
case List(value) => "b"
case _ => "c"
}
I'm not so sure if it's a good idea (i.e. readable). But a neat exercise nonetheless.
It would be nice if you could match on tuples: case (value1, value2) => ... instead of lists.
How about this:
Welcome to Scala version 2.8.0.r20327-b20091230020149 (Java HotSpot(TM) Client VM, Java 1.6.0_17).
Type in expressions to have them evaluated.
Type :help for more information.
scala> def m(v1: Any,v2: Any) = (v1,v2) match {
| case (Some(x),Some(y)) => "a"
| case (Some(_),None) | (None,Some(_)) => "b"
| case _ => "c"
| }
m: (v1: Any,v2: Any)java.lang.String
scala> m(Some(1),Some(2))
res0: java.lang.String = a
scala> m(Some(1),None)
res1: java.lang.String = b
scala> m(None,None)
res2: java.lang.String = c
scala>
You should be able to do it if you define it as a val first:
val MyValThatIsCapitalized = new OneAndOnlyOne(v: Option[Foo] => v.isDefined )
val result = (v1,v2) match {
case (Some(value1), Some(value2)) => "a"
case MyValThatIsCapitalized(value) => "b"
case _ = > "c"
}
As implied by the name, the name of the val containing the extractor object must be capitalized.
On Scala 2.8:
val result = List(v1,v2).flatten match {
case List(value1, value2) => "a"
case List(value) => "b"
case _ = > "c"
}
On Scala 2.7, however, you need a type hint to make it work. So, assuming value is Int, for instance, then:
val result = (List(v1,v2).flatten : List[Int]) match {
case List(value1, value2) => "a"
case List(value) => "b"
case _ = > "c"
}
The funny thing about it is that I misread "first" as "list" on Mitch Blevins answer, and that gave me this idea. :-)
Since you already matched against (Some(x), Some(y)), you may match against (None, None) explicitly, and the remaining cases are (Some(x), None) and (None, Some(y)):
def decide [T](v1: Option[T], v2:Option[T]) = (v1, v2) match {
case (Some (x), Some (y)) => "a"
case (None, None) => "c"
case _ => "b"
}
val ni : Option [Int] = None
decide (ni, ni) // c
decide (Some (4), Some(3)) // a
decide (ni, Some (3)) // b
decide (Some (4), ni) // b