scala pattern matching on functions - scala

I am looking for a way to do pattern matching based on the result of a function evaluation rather than the type of the val. For example,
def f1(x:String):Boolean = if (x contains ("Helllo")) true else false
val caller="Hello"
caller match
{
case f1(caller) => println ("caller said hello")
case _ => println ("caller did not say hello")
}
any idea ?

You want to use pattern guards:
caller match
{
case x if f1(x) => println ("caller said hello")
case _ => println ("caller did not say hello")
}

I would prefer to do it without guard, that would a bit faster and cleaner:
f1(caller) match {
case true => ....
case false => ....
}
but for Boolean better to use if/else expression, that would be cleaner in byte code and a bit faster

Related

How to return upon encountering first "true" in a List[IO[Boolean]] in Scala Cats Effect

Say I have a set of rules that have a validation function that returns IO[Boolean] at runtime.
case class Rule1() {
def validate(): IO[Boolean] = IO.pure(false)
}
case class Rule2() {
def validate(): IO[Boolean] = IO.pure(false)
}
case class Rule3() {
def validate(): IO[Boolean] = IO.pure(true)
}
val rules = List(Rule1(), Rule2(), Rule3())
Now I have to iterate through these rules and see "if any of these rules" hold valid and if not then throw exception!
for {
i <- rules.map(_.validate()).sequence
_ <- if (i.contains(true)) IO.unit else IO.raiseError(new RuntimeException("Failed"))
} yield ()
The problem with the code snippet above is that it is trying to evaluate all the rules! What I really want is to exit at the encounter of the first true validation.
Not sure how to achieve this using cats effects in Scala.
I claim that existsM is the most direct way to achieve what you want. It behaves pretty much the same as exists, but for monadic predicates:
for {
t <- rules.existsM(_.validate())
_ <- IO.raiseUnless(t)(new RuntimeException("Failed"))
} yield ()
It also stops the search as soon as it finds the first true.
The raiseUnless is just some syntactic sugar that's equivalent to the if-else from your question.
If you take a look at list of available extension methods in your IDE, you can find findM:
for {
opt <- rules.findM(_.validate())
_ <- opt match {
case Some(_) => IO.unit
case None => IO.raiseError(new RuntimeException("Failed")
}
} yield ()
Doing it manually could be done with foldLeft and flatMap:
rules.foldLeft(IO.pure(false)) { (valueSoFar, nextValue) =>
valueSoFar.flatMap {
case true => IO.pure(true) // can skip evaluating nextValue
case false => nextValue.validate() // need to find the first true IO yet
}
}.flatMap {
case true => IO.unit
case false => IO.raiseError(new RuntimeException("Failed")
}
The former should have the additional advantage that it doesn't have to iterate over whole collection when it finds the first match, while the latter will still go through all items, even if will start discarding them at some point. findM solves that by using tailRecM internally to terminate the iteration on first met condition.
You can try recursive
def firstTrue(rules: List[{def validate(): IO[Boolean]}]): IO[Unit] = rules match {
case r :: rs => for {
b <- r.validate()
res <- if (b) IO.unit else firstTrue(rs)
} yield res
case _ => IO.raiseError(new RuntimeException("Failed"))
}
Another approach is not using booleans at all, but the monad capabilities of IO
def validateRules(rules: List[Rule]): IO[Unit] =
rules.traverse_ { rule =>
rule.validate().flatMap { flag =>
IO.raiseUnless(flag)(new RuntimeException("Failed"))
}
}

scala: updating string value in an option

I have an Option of a string. I want to update the contained value:
if(x.isEmpty) {
...another calculation
} else {
x.map(val => ...update val)
}
Is this an idiomatic way?
x.fold(another calculation)(v => ...update v)
e.g.
x.fold("no value")("Value is " + _)
Note that this extracts the value from the Option so if you want to have the result as an Option you need to wrap it in Some.
Note that if your inner computation gets too long or unreadable for a fold, there's always good old-fashioned pattern matching.
x match {
case None => {
// None case ...
}
case Some(y) => {
// Some case (y is the inside) ...
}
}
Like everything in Scala, this is an expression, so it can be assigned to a variable or used in another other expression you like.
Alternatively, using the lazy keyword:
// T is the type of the value
val valueOpt: Option[T] = ???
lazy val backupValue: T = ??? // Other calculation, but only evaluated if needed
val value: T = valueOpt.map( v => /*Update v*/ ).getOrElse( backupValue )
// do something with the value you want to manipulate

map expression in case clause in scala pattern matching

I have a configuration value that matches to one of the values in a map and depending on to which it matches i take an action. Here is some sample code of what i am trying to do
val x = 1 // or 2 or 3
val config = Map("c1"-> 1, "c2"-> 2, "c3"-> 3)
x match {
case config("c1") =>
println("1")
case config("c2") =>
println("2")
case config("c3") =>
println("3")
}
Now this should print 1 because config("c1") evaluates to 1 but it gives error
error: value config is not a case class, nor does it have an unapply/unapplySeq member
case config("c1") =>
Similarly for the other 2 cases. Why should i have an unapply here? Any pointers?
An expression like that looks like an extractor, hence the message about unapply/unapplySeq methods. If you don't want to use an extractor but just want to match against a plain value, you need to store that value in a stable identifier - you can't use an arbitrary expression as a match case:
val case1 = config("c1")
x match {
case case1 => println("1")
...
}
To the best of my knowledge, in Scala, x match {case config("c1") gets translated to config.unapply(x) with the branching dependent on the result of the unapply method. As Imm already mentioned in his answer, this isn't the case for stable identifiers (literals and val), and I'd encourage you to use his solution.
Nevertheless, to show you how you could solve the problem using extractors, I'd like to post a different solution:
def main(args: Array[String]): Unit = {
object config {
val configData = Map("c1" -> 1, "c2" -> 2, "c3" -> 3)
def unapply(value: Int): Option[String] = configData find (_._2 == value) map (_._1)
}
1 to 4 foreach {
case config("c1") => println("1")
case config("c2") => println("2")
case config("c3") => println("3")
case _ => println("no match")
}
}
I changed the match for a foreach to show the different results, but this has no effect on the implementation. This would print:
1
2
3
no match
As you can see, case config("c1") now calls the unapply method and checks whether the result is Some("c1"). Note that this is inverse to how you'd use a map: The key is searched according to the value. However, this makes sense: If in the map, "c1" and "c2" both map to 1, then 1 matches both, the same way _ matches everything, in our case even 4 which is not configured.
Here's also a very brief tutorial on extractors. I don't find it particularly good, because both, the returned type and the argument type are Int, but it might help you understand what's going on.
As others have stated, with x match { case config("c1") => ..., scala looks for an extractor by the name of config (something with an unapply method that takes a single value and returns an Optional value); Making pattern matching work this way seems like an abuse of the pattern, and I would not use an extractor for this.
Personally, I would recommend one of the following:
if (x == config("c1"))
println("1")
else if (x == config("c2"))
println("2")
else ...
Or, if you're set on using a match statement, you can use conditionals like this:
x match {
case _ if x == config("c1") =>
println("1")
case _ if x == config("c2") =>
println("2")
case _ if x == config("c3") =>
println("3")
}
Not as clean; unfortunately, there isn't a way to invoke a method call literally where the extractor goes. You can use back-ticks to tell scala "match against the value of this variable" (rather than default behavior, which would yield the value named as that variable):
val (c1,c2,c3) = (config("c1"), config("c2"), config("c3"))
x match {
case `c1` =>
println("1")
case `c2` =>
println("2")
case `c3` =>
println("3")
}
Finally, if your goal is to reverse-apply a map, maybe try this instead?
scala> Map("a" -> 1).map { case (k,v) => (v,k) }
res0: scala.collection.immutable.Map[Int,String] = Map(1 -> a)

Tail recursion issue

We were experimenting with parallel collections in Scala and wanted to check whether the result was ordered. For that, I wrote a small function on the REPL to do that check on the very large List we were producing:
def isOrdered(l:List[Int]):Boolean = { l match {
case Nil => true
case x::Nil => true
case x::y::Nil => x>y
case x::y::tail => x>y & isOrdered(tail)
}
}
It fails with a stackOverflow (how appropriate for a question here!).
I was expecting it to be tail-optimized. What's wrong?
isOrdered is not the last call in your code, the & operator is. Try this instead:
#scala.annotation.tailrec def isOrdered(l:List[Int]):Boolean = { l match {
case Nil => true
case x::Nil => true
case x::y::Nil => x>y
case x::y::tail => if (x>y) isOrdered(tail) else false
}
}
Your algorithm is incorrect. Even with #Kim's improvement, isOrdered(List(4,3,5,4)) returns true.
Try this:
def isOrdered(l:List[Int]): Boolean = l match {
case Nil => true
case x :: Nil => true
case x :: y :: t => if (x <= y) isOrdered(l.tail) else false
}
(also updated so that signs are correct)
edit: my perferred layout would be this:
def isOrdered(list: List[Int]): Boolean = list match {
case Nil => true
case x :: Nil => true
case x :: xs => if (x > xs.head) false
else isOrdered(xs)
}
The quick way if performance isn't a problem would be
def isOrdered(l: List[Int]) = l == l.sorted
It can't be tail-optimized because you return this: 'x>y & isOrdered(tail)'. It means it will need to keep it on the stack.
Use the #tailrec annotation to force an error when you expect functions to be tail-recursive. It will also explain why it can't be.
I think the problem is that you're using the bitwise-and operator (&) in your last case. Since the runtime needs to know the value of the isOrdered call before it can evaluate the &, it can't tail-optimize the function. (That is, there is more code to run--the bitwise-and operation--after isOrdered is called.)
Using && or an if statement may help.

scheme cond in scala language

Does scala have an equivalent to scheme's cond?
I guess you're looking for match (or just simply if/else if/else).
case class Paired(x: Int, y: Int)
def foo(x: Any) = x match {
case string : String => println("Got a string")
case num : Int if num < 100 => println("Number less than 100")
case Paired(x,y) => println("Got x and y: " + x + ", " + y)
case unknown => println("??: " + unknown)
}
The first two case statements show type based pattern matching. The third shows the use of an Extractor to break data down into constituent parts and to assign those parts to variables. The third shows a variable pattern match which will match anything. Not shown is the _ case:
case _ => println("what")
Which like the variable pattern match, matches anything, but does not bind the matched object to a variable.
The case class at the top is Scala shorthand for creating an extractor as well as the class itself.
Of course, neither match nor if does exactly the same thing as cond. One possibility is to do like this:
object Cond {
def apply(clauses: Iterable[(()=>Boolean, ()=>Any)]): Any = {
clauses find (_._1()) map (_._2()) getOrElse ()
}
}
This object accepts something Iterable where each item is a pair of a function returning Boolean and a function returning Any. It tries to find an item whose first function returns true, stops looking if it finds one, calls the second function on a found item and returns the result of that function (or () if none was found).
Examples:
val clauses = Seq(
({()=>false}, {()=>println("foo")}),
({()=>true}, {()=>println("bar")})
)
Cond(clauses)
def checkYear(year: Int) = {
Cond(Seq(
({()=>year % 400 == 0}, {()=>42}),
({()=>true}, {()=>{c:Char => (c.toString * 3)}})
))
}
ETA: Yes, I know it is ugly, but it works.
The most straightforward translation is to use pattern guards, although it requires some boilerplate. Pattern guards only work in a case pattern, and case only works in a match (unless we're writing a PartialFunction).
We can satisfy these conditions by matching a unit value against trivial cases:
;; Scheme
(cond
(foo bar)
(baz quux)
(t mydefault))
// Scala
() match {
case _ if foo => bar
case _ if baz => quux
case _ => mydefault
}