I have a match statement like this:
i match {
case x if x == 0 ⇒
romanNumeral
case x if x >= 1000 ⇒
this.roman(i - 1000, s"${romanNumeral}M")
case x if x >= 900 ⇒
this.roman(i - 900, s"${romanNumeral}CM")
// etc.
Depending on how this is formatted, it could be about 30 lines of redundant code.
So I'm wondering whether it is possible to make this code more dry.
So I created a partial function:
private def toRoman(upperGuard: Int, token: String, romanNumeral: String): String = {
case value: Int if value >= upperGuard ⇒
this.roman(upperGuard - 1, s"$romanNumeral$token")
}
which I then tried to include into the above matcher like:
i match {
case x if x == 0 ⇒
romanNumeral
toRoman(1000, "M", romanNumeral)
toRoman(900, "CM", romanNumeral)
// etc.
... But this won't work because Scala's compiler doesn't recognize these functions are the case statements it is looking for.
Is there any way to make this work?
You could create your cases as partial functions:
private def toRoman(upperGuard: Int, token: String, romanNumeral: String): PartialFunction[Int, String] = {
case value if value >= upperGuard =>
this.roman(upperGuard - 1, s"$romanNumeral$token")
}
val firstCase: PartialFunction[Int, String] = {
case x if x == 0 => romanNumeral
}
And then compose it like this:
val toRomanPartialFunction = firstCase
.orElse(toRoman(1000, "M", romanNumeral))
.orElse(toRoman(900, "CM", romanNumeral))
After that you could use it like regular function:
toRomanPartialFunction.apply(443)
toRomanPartialFunction(443)
So you basically want to make the code less repetitive, first things first:
Scala´s compiler doesn't recognise these functions as case statements because they are functions;
Second thing, that function is not actually a partial function;
Finally, those matches are ok to be like that, if you find a way of reducing lines of code by grouping in some kind of function like you did great but I don't find them redundant, unless you can redo it with a function like I said.
Ps: That function don't do the some thing as the case
You don't have a pattern matching expression, you are just writing an if else statement. If you want to return a function, you would write: x => this.something(x,"foo-bar") You have no need for case x. If you are only having one expression on the LHS case x you have no need for pattern matching, and can just use if else. Pattern matching without a class hierarchy doesn't make sense.
Related
I have an Option instance, say O, which contains an instance of a class, say A, and A itself has some Options inside it.
I have to achieve something like this, expressed in pseudo code as:
if(A.x exists) {
if(A.y exists) {
//extract values from some another Option Z embedded in A
} else {
// return Option of some default value
}
}
So I try this:
O.filter(some filter condition to have only some specific types of A).filter(!A.x.isEmpty).filter(!A.y.isEmpty).flatMap(_.z.somevalue).orElse(Some("Some default value"))
Is this the correct way, OR do I need to use pattern matching at some point?
Edit: Result should be an Option[String].O si an Option[A]. A is a class with fields x,y,z, and all three are Option of String.
This looks like a good use case for pattern matching.
For what I understood of your question you want something like this:
(if not, the code should be easy to adjust)
final case class A(x: Option[String], x: Option[String], x: Option[String])
def getData(oa: Option[A]): Option[String] = oa match {
case Some(A(Some(_), Some(_), z)) => z
case None => None
case _ => Some("Default Value")
}
The cleanest expression of this would be
A.x.map(x => A.y.fold(default_value)(y => calculation_using_y))
Suppose I have a Seq(1, 2, 3, 4, 5) and I want to know if value "4" exists in it. I want to know if it is possible to find and extract the answer only using pattern matching.
Seq(1, 2, 3, 4, 5) match {
case Seq(_, 4, _*) => true
case _ => false
}
match clauses like this only works if the position of our specified value is known. I am curious to know if it is possible to do this in Scala, I am new to Scala and not completely familiar with its syntax and features.
obviously using the if gaurd is not helpful because it does not allow extracting the value to a variable.
you may ask why it is even important and why not use current existing exists or filter methods. Imagine the case below.
case class Score(eventName: String, amount: Integer)
case class Person(name: String, scores: Seq[Score])
suppose I have a collection of Persons and I want to find the highest score for a certain event. a person may have a score for that event or may not.
persons.collect({
case x # _ if x.scores.exists(_.eventName == "event1") =>
x.scores.find(_.eventName == "event1").get.amount
}).max
the problem is that the filter on eventName is processed two times.
I know it is possible to do this using filter and map with mutiple iterations. but I am interested to know if there is a solution using pattern matching, with pattern matching you can find and extract the value to a variable at the same time.
You can write a custom matcher with an unapply method:
case class EventScore(eventName: String) {
def unapply(person: Person): Option[Int] =
person.scores.collectFirst { case s if s.eventName == eventName => s.amount }
}
val score = EventScore("event1")
persons.collect({
case score(amount) => amount
}).max
You might be able to do it by pattern matching inside a recursive method but I think this is all you need:
persons.flatMap(_.scores.filter(_.eventName == "ev1")
.map(_.amount))
.maxOption
.getOrElse(0)
Or the prettier for comprehension:
(for {
person <- persons
score <- person.scores
if score.eventName == "ev1"
} yield score.amount).maxOption.getOrElse(0)
//using only pattern matching
def has(xs: Seq[Int], target: Int) : Boolean = xs match {
case Seq() => false
case Seq(`target`, _ #_*) => true
case Seq(_, tl #_*) => has(tl, target)
}
testing:
has(List(2,4,5,11,44,66), 11) //true
has(List(2,4,5,11,44,66), 12) //false
has(List(2,4,5,11,44,66), 66) //true
There is no way currently to introduce term inside guard part of pattern matching (I mean if ... part). I was looking for something like that but without luck.
In your example tho you don't need it. Few words about example:
Using two brackets is not necessary collect({..}).
# _ in case is not necessary either
.max will blow on empty collection. It is especially risky with collect
Here is my proposition:
persons.map {
case x => x.scores.find(_.eventName == "event1").getOrElse(0)
}.max
I have a method that receives a function, but that function may be partial, in such case I don't want it to fail with MatchError.
def doSomething[X,Y](opt:Option[X])(f:X=>Y)={
f match {
case p:PartialFunction[X,Y]=> opt.flatMap(p.lift) //This doesn't seem to work
case _ => opt.map(f)
}
}
That way I can use the method like this
doSomething(x){
case t if predicate(t) => otherMethod(t)
}
so in case I don't have a predicate, I can use it like
this doSomething(x)(otherMethod) instead of
doSoemthing(x){
case t=> otherMethod(t)
}
Note: Looking for a solution that doesn't require catching MatchError exceptions
This isn't an answer because I don't think that what you want is possible in Scala.
The original method is fine and works as expected, though it could be a bit simpler:
def doSomething[X, Y](opt: Option[X])(f: X => Y): Option[Y] = {
f match {
case p: PartialFunction[X, Y] => opt.collect(p)
case _ => opt.map(f)
}
}
The problem is here:
doSomething(x){
case t if predicate(t) => otherMethod(t)
}
Scala is creating a Function rather than a PartialFunction from that match expression so the test is failing. If you pass a real PartialFunction the method works OK.
val p: PartialFunction[Int, Int] = {
case i: Int if i > 0 => i
}
doSomething(Some(0))(p) // Returns None
I don't think there is any way of doing what you want, mainly because doSomething has multiple argument lists which messes up type deduction for the second argument list.
My suggestion is just to use
x.map(f)
or
x.collect{
case ...
}
as appropriate in the calling code.
The syntax for partial function has been changed since 2.9 per SLS 8.5, so that even you do { case x => y}, it DOES NOT mean it is a partial function. Its type will be exact as you define it as.
In your case, you defined it as X=>Y (as in your function parameter), so it is just a X=>Y (it got compiled into a regular function, and non match cases will throw MatchError), and even you do isInstanceOf[PartialFunciton[_,_]], it won't match.
To make your scenario work, you can just simply cast the passed function as PartialFunction, like:
doSomething(Some(1))({case 2 => 0}: PartialFunction[Int,Int]) //This returns None without MatchError
while
doSomething(Some(1)){case 2 => 0} //This gives MatchError and it is not recognized as PartialFunction inside the body
This is probably not as convenient as you thought it is, but it is the only way to make it work. (or you define 2 separate functions for either case, like collect and map in standard library)
I'm not sure what you are passing as a Partial Function, but definitely you should have to define it with specific signature like this:
val positive: PartialFunction[Int, Option[Int]] = {
case x if x >= 0 => Some(x)
case _ => None
The positive function is defined only for positive numbers. In case of negative numbers, the function returns None and you won't get scala.MatchError in runtime.
This specific function enables you to access to isDefinedAt method which is testing dynamically if a value is in the domain of the function.
postive(5).isDefinedAt // true
poistive.isInstanceOf[PartialFunction[Int, Option[Int]]] // true
I demonstrated here why you are always getting false when you check p.isInstanceOf
def doSomething[X,Y](opt:Option[X])(f:X=>Y)={
f match {
case p if p.isInstanceOf[PartialFunction[X,Y]] =>
println("I'm a pf")
println(s"Is it PartialFunction: ${p.isInstanceOf[PartialFunction[X,Y]]}")
opt.map(p)
case _ =>
println("I'm not a pf")
opt.map(f)
}
}
doSomething[Int, Option[Int]](Some(5))(positive) // partial function case
doSomething[Int, String](Some(5)) { // tricky case
case s => s.toString
}
You can play with it here:
I found myself writing something like this quite often:
a match {
case `b` => // do stuff
case _ => // do nothing
}
Is there a shorter way to check if some value matches a pattern? I mean, in this case I could just write if (a == b) // do stuff, but what if the pattern is more complex? Like when matching against a list or any pattern of arbitrary complexity. I'd like to be able to write something like this:
if (a matches b) // do stuff
I'm relatively new to Scala, so please pardon, if I'm missing something big :)
This is exactly why I wrote these functions, which are apparently impressively obscure since nobody has mentioned them.
scala> import PartialFunction._
import PartialFunction._
scala> cond("abc") { case "def" => true }
res0: Boolean = false
scala> condOpt("abc") { case x if x.length == 3 => x + x }
res1: Option[java.lang.String] = Some(abcabc)
scala> condOpt("abc") { case x if x.length == 4 => x + x }
res2: Option[java.lang.String] = None
The match operator in Scala is most powerful when used in functional style. This means, rather than "doing something" in the case statements, you would return a useful value. Here is an example for an imperative style:
var value:Int = 23
val command:String = ... // we get this from somewhere
command match {
case "duplicate" => value = value * 2
case "negate" => value = -value
case "increment" => value = value + 1
// etc.
case _ => // do nothing
}
println("Result: " + value)
It is very understandable that the "do nothing" above hurts a little, because it seems superflous. However, this is due to the fact that the above is written in imperative style. While constructs like these may sometimes be necessary, in many cases you can refactor your code to functional style:
val value:Int = 23
val command:String = ... // we get this from somewhere
val result:Int = command match {
case "duplicate" => value * 2
case "negate" => -value
case "increment" => value + 1
// etc.
case _ => value
}
println("Result: " + result)
In this case, you use the whole match statement as a value that you can, for example, assign to a variable. And it is also much more obvious that the match statement must return a value in any case; if the last case would be missing, the compiler could not just make something up.
It is a question of taste, but some developers consider this style to be more transparent and easier to handle in more real-world examples. I would bet that the inventors of the Scala programming language had a more functional use in mind for match, and indeed the if statement makes more sense if you only need to decide whether or not a certain action needs to be taken. (On the other hand, you can also use if in the functional way, because it also has a return value...)
This might help:
class Matches(m: Any) {
def matches[R](f: PartialFunction[Any, R]) { if (f.isDefinedAt(m)) f(m) }
}
implicit def any2matches(m: Any) = new Matches(m)
scala> 'c' matches { case x: Int => println("Int") }
scala> 2 matches { case x: Int => println("Int") }
Int
Now, some explanation on the general nature of the problem.
Where may a match happen?
There are three places where pattern matching might happen: val, case and for. The rules for them are:
// throws an exception if it fails
val pattern = value
// filters for pattern, but pattern cannot be "identifier: Type",
// though that can be replaced by "id1 # (id2: Type)" for the same effect
for (pattern <- object providing map/flatMap/filter/withFilter/foreach) ...
// throws an exception if none of the cases match
value match { case ... => ... }
There is, however, another situation where case might appear, which is function and partial function literals. For example:
val f: Any => Unit = { case i: Int => println(i) }
val pf: PartialFunction[Any, Unit] = { case i: Int => println(i) }
Both functions and partial functions will throw an exception if called with an argument that doesn't match any of the case statements. However, partial functions also provide a method called isDefinedAt which can test whether a match can be made or not, as well as a method called lift, which will turn a PartialFunction[T, R] into a Function[T, Option[R]], which means non-matching values will result in None instead of throwing an exception.
What is a match?
A match is a combination of many different tests:
// assign anything to x
case x
// only accepts values of type X
case x: X
// only accepts values matches by pattern
case x # pattern
// only accepts a value equal to the value X (upper case here makes a difference)
case X
// only accepts a value equal to the value of x
case `x`
// only accept a tuple of the same arity
case (x, y, ..., z)
// only accepts if extractor(value) returns true of Some(Seq()) (some empty sequence)
case extractor()
// only accepts if extractor(value) returns Some something
case extractor(x)
// only accepts if extractor(value) returns Some Seq or Tuple of the same arity
case extractor(x, y, ..., z)
// only accepts if extractor(value) returns Some Tuple2 or Some Seq with arity 2
case x extractor y
// accepts if any of the patterns is accepted (patterns may not contain assignable identifiers)
case x | y | ... | z
Now, extractors are the methods unapply or unapplySeq, the first returning Boolean or Option[T], and the second returning Option[Seq[T]], where None means no match is made, and Some(result) will try to match result as described above.
So there are all kinds of syntactic alternatives here, which just aren't possible without the use of one of the three constructions where pattern matches may happen. You may able to emulate some of the features, like value equality and extractors, but not all of them.
Patterns can also be used in for expressions. Your code sample
a match {
case b => // do stuff
case _ => // do nothing
}
can then be expressed as
for(b <- Some(a)) //do stuff
The trick is to wrap a to make it a valid enumerator. E.g. List(a) would also work, but I think Some(a) is closest to your intended meaning.
The best I can come up with is this:
def matches[A](a:A)(f:PartialFunction[A, Unit]) = f.isDefinedAt(a)
if (matches(a){case ... =>}) {
//do stuff
}
This won't win you any style points though.
Kim's answer can be “improved” to better match your requirement:
class AnyWrapper[A](wrapped: A) {
def matches(f: PartialFunction[A, Unit]) = f.isDefinedAt(wrapped)
}
implicit def any2wrapper[A](wrapped: A) = new AnyWrapper(wrapped)
then:
val a = "a" :: Nil
if (a matches { case "a" :: Nil => }) {
println("match")
}
I wouldn't do it, however. The => }) { sequence is really ugly here, and the whole code looks much less clear than a normal match. Plus, you get the compile-time overhead of looking up the implicit conversion, and the run-time overhead of wrapping the match in a PartialFunction (not counting the conflicts you could get with other, already defined matches methods, like the one in String).
To look a little bit better (and be less verbose), you could add this def to AnyWrapper:
def ifMatch(f: PartialFunction[A, Unit]): Unit = if (f.isDefinedAt(wrapped)) f(wrapped)
and use it like this:
a ifMatch { case "a" :: Nil => println("match") }
which saves you your case _ => line, but requires double braces if you want a block instead of a single statement... Not so nice.
Note that this construct is not really in the spirit of functional programming, as it can only be used to execute something that has side effects. We can't easily use it to return a value (therefore the Unit return value), as the function is partial — we'd need a default value, or we could return an Option instance. But here again, we would probably unwrap it with a match, so we'd gain nothing.
Frankly, you're better off getting used to seeing and using those match frequently, and moving away from this kind of imperative-style constructs (following Madoc's nice explanation).
I have a recursive function that takes a Map as single parameter. It then adds new entries to that Map and calls itself with this larger Map. Please ignore the return values for now. The function isn't finished yet. Here's the code:
def breadthFirstHelper( found: Map[AIS_State,(Option[AIS_State], Int)] ): List[AIS_State] = {
val extension =
for(
(s, v) <- found;
next <- this.expand(s) if (! (found contains next) )
) yield (next -> (Some(s), 0))
if ( extension.exists( (s -> (p,c)) => this.isGoal( s ) ) )
List(this.getStart)
else
breadthFirstHelper( found ++ extension )
}
In extension are the new entries that shall get added to the map. Note that the for-statement generates an iterable, not a map. But those entries shall later get added to the original map for the recursive call. In the break condition, I need to test whether a certain value has been generated inside extension. I try to do this by using the exists method on extension. But the syntax for extracting values from the map entries (the stuff following the yield) doesn't work.
Questions:
How do I get my break condition (the boolean statement to the if) to work?
Is it a good idea to do recursive work on a immutable Map like this? Is this good functional style?
When using a pattern-match (e.g. against a Tuple2) in a function, you need to use braces {} and the case statement.
if (extension.exists { case (s,_) => isGoal(s) } )
The above also uses the fact that it is more clear when matching to use the wildcard _ for any allowable value (which you subsequently do not care about). The case xyz gets compiled into a PartialFunction which in turn extends from Function1 and hence can be used as an argument to the exists method.
As for the style, I am not functional programming expert but this seems like it will be compiled into a iterative form (i.e. it's tail-recursive) by scalac. There's nothing which says "recursion with Maps is bad" so why not?
Note that -> is a method on Any (via implicit conversion) which creates a Tuple2 - it is not a case class like :: or ! and hence cannot be used in a case pattern match statement. This is because:
val l: List[String] = Nil
l match {
case x :: xs =>
}
Is really shorthand/sugar for
case ::(x, xs) =>
Similarly a ! b is equivalent to !(a, b). Of course, you may have written your own case class ->...
Note2: as Daniel says below, you cannot in any case use a pattern-match in a function definition; so while the above partial function is valid, the following function is not:
(x :: xs) =>
This is a bit convoluted for me to follow, whatever Oxbow Lakes might think.
I'd like first to clarify one point: there is no break condition in for-comprehensions. They are not loops like C's (or Java's) for.
What an if in a for-comprehension means is a guard. For instance, let's say I do this:
for {i <- 1 to 10
j <- 1 to 10
if i != j
} yield (i, j)
The loop isn't "stopped" when the condition is false. It simply skips the iterations for which that condition is false, and proceed with the true ones. Here is another example:
for {i <- 1 to 10
j <- 1 to 10
if i % 2 != 0
} yield (i, j)
You said you don't have side-effects, so I can skip a whole chapter about side effects and guards on for-comprehensions. On the other hand, reading a blog post I made recently on Strict Ranges is not a bad idea.
So... give up on break conditions. They can be made to work, but they are not functional. Try to rephrase the problem in a more functional way, and the need for a break condition will be replaced by something else.
Next, Oxbow is correct in that (s -> (p,c) => isn't allowed because there is no extractor defined on an object called ->, but, alas, even (a :: b) => would not be allowed, because there is no pattern matching going on in functional literal parameter declaration. You must simply state the parameters on the left side of =>, without doing any kind of decomposition. You may, however, do this:
if ( extension.exists( t => val (s, (p,c)) = t; this.isGoal( s ) ) )
Note that I replaced -> with ,. This works because a -> b is a syntactic sugar for (a, b), which is, itself, a syntactic sugar for Tuple2(a, b). As you don't use neither p nor c, this works too:
if ( extension.exists( t => val (s, _) = t; this.isGoal( s ) ) )
Finally, your recursive code is perfectly fine, though probably not optimized for tail-recursion. For that, you either make your method final, or you make the recursive function private to the method. Like this:
final def breadthFirstHelper
or
def breadthFirstHelper(...) {
def myRecursiveBreadthFirstHelper(...) { ... }
myRecursiveBreadthFirstHelper(...)
}
On Scala 2.8 there is an annotation called #TailRec which will tell you if the function can be made tail recursive or not. And, in fact, it seems there will be a flag to display warnings about functions that could be made tail-recursive if slightly changed, such as above.
EDIT
Regarding Oxbow's solution using case, that's a function or partial function literal. It's type will depend on what the inference requires. In that case, because that's that exists takes, a function. However, one must be careful to ensure that there will always be a match, otherwise you get an exception. For example:
scala> List(1, 'c') exists { case _: Int => true }
res0: Boolean = true
scala> List(1, 'c') exists { case _: String => true }
scala.MatchError: 1
at $anonfun$1.apply(<console>:5)
... (stack trace elided)
scala> List(1, 'c') exists { case _: String => true; case _ => false }
res3: Boolean = false
scala> ({ case _: Int => true } : PartialFunction[AnyRef,Boolean])
res5: PartialFunction[AnyRef,Boolean] = <function1>
scala> ({ case _: Int => true } : Function1[Int, Boolean])
res6: (Int) => Boolean = <function1>
EDIT 2
The solution Oxbow proposes does use pattern matching, because it is based on function literals using case statements, which do use pattern matching. When I said it was not possible, I was speaking of the syntax x => s.