Scala: PartialFunction weird behavior - scala

It's weird but my code prints u. Any ideas why does it do such stuff?
object PF extends App {
val f1: PartialFunction[Int, String] = {
case x: Int if x % 2 == 0 => "2"
}
val f2: PartialFunction[Int, String] = {
case x: Int if x % 3 == 0 => "3"
}
val f3: PartialFunction[Int, String] = {
case x: Int if x % 5 == 0 => "5"
}
val result = f1.orElse(f2.orElse(f3.orElse("<undef>")))
println(result.apply(1))
}

Your code interprets the string "" as PartialFunction:
val result: PartialFunction[Int, String] = "<undef>"
result.apply(1) // second character of "<undef>" --> u
This happens through an implicit conversion from String to WrappedString which is a subtype of Seq[Char]. Further, Seq[T] is a subtype of PartialFunction[Int, T] (given an index, get an element of the Seq if it exists).
The last line reaches this case, since 1 is not divisible by any of 2,3,5 (so it falls through f1, f2 and f3).
What you would want instead is applyOrElse:
val fun = f1 orElse f2 orElse f3
fun.applyOrElse(1, "<undef>") // --> "<undef>"
Alternatively, you can specify a fallback partial function:
val result = f1 orElse f2 orElse f3 orElse {
case _ => "<undef>"
}

Related

How to use pattern matching with function values in Scala

I have several functions with same input and output types initialized in an object
object Utils {
def f1(value: Int): Double = ???
def f2(value: Int): Double = ???
def f3(value: Int): Double = ???
}
I have a list of higher order values for those functions:
val x = List(Utils.f1, Utils.f2)
How can I use pattern matching to check which functions of those declared in the object are contained in x? I would like to obtain something similar to the following code:
x(0) match {
case Utils.f1 => ...
case Utils.f2 => ...
}
You can't match against functions, it has no meaningfully defined equality.
This will be possible if you make f1, f2, f3 vals. Please notice that upon pattern matching the equality by reference will be used
object Utils {
val f1: Int => Double = _ * 10.0
val f2: Int => Double = _ * 20.0
val f3: Int => Double = _ * 30.0
}
val x: Seq[Int => Double] = List(Utils.f1, Utils.f2)
import Utils._
x(0) match {
case `f1` => println(1)
case `f2` => println(2)
case `f3` => println(3)
}
If you keep f1, f2, f3 defs then
object Utils {
def f1(value: Int): Double = value * 10.0
def f2(value: Int): Double = value * 20.0
def f3(value: Int): Double = value * 30.0
}
val x: Seq[Int => Double] = List(Utils.f1, Utils.f2)
val f1: Int => Double = Utils.f1
val f2: Int => Double = Utils.f2
val f3: Int => Double = Utils.f3
x(0) match {
case `f1` => println(1)
case `f2` => println(2)
case `f3` => println(3)
}
produces MatchError.

Combine 2 partial functions

I have two partial functions returning unit (f1, f2). For instance, something like that:
val f1 = {
case s: arg => //do some
//etc... lots of cases
}
val f2 = {
case s: anotherArg => //do some
//lots of cases
}
Is there a concise way to compose this to partial functions the way as that if
f(x) = {f1(x); f2(x)} iff f1.isDefinedAt(x) && f2.isDefinedAt(x)
f(x) = f1(x); iff f1.isDefinedAt(x) && !f2.isDefinedAt(x)
f(x) = f2(x); iff !f1.isDefinedAt(x) && f2.isDefinedAt(x)
orElse
f1 orElse f2
Scala REPL
scala> val f: PartialFunction[Int, Int] = { case 1 => 1 }
f: PartialFunction[Int,Int] = <function1>
scala> val g: PartialFunction[Int, Int] = { case 2 => 2 }
g: PartialFunction[Int,Int] = <function1>
scala> val h = f orElse g
h: PartialFunction[Int,Int] = <function1>
scala> h(1)
res3: Int = 1
scala> h(2)
res4: Int = 2
scala> h.isDefinedAt(1)
res6: Boolean = true
scala> h.isDefinedAt(2)
res7: Boolean = true
Both both functions to execute on common cases
Using List of partial functions and foldLeft
Scala REPL
scala> val f: PartialFunction[Int, Int] = { case 1 => 1 case 3 => 3}
f: PartialFunction[Int,Int] = <function1>
scala> val g: PartialFunction[Int, Int] = { case 2 => 2 case 3 => 3}
g: PartialFunction[Int,Int] = <function1>
scala> val h = f orElse g
h: PartialFunction[Int,Int] = <function1>
scala> h(3)
res10: Int = 3
scala> h(3)
res11: Int = 3
scala> val h = List(f, g)
h: List[PartialFunction[Int,Int]] = List(<function1>, <function1>)
scala> def i(arg: Int) = h.foldLeft(0){(result, f) => if (f.isDefinedAt(arg)) result + f(arg) else result }
i: (arg: Int)Int
scala> i(3)
res12: Int = 6
Although pamu's answer is good, I don't like the fact that it is bound to specific Int type. Unfortunately you didn't specify result type well enough, so I see 3 alternatives:
You want to get list of all results of all defined functions and you don't care about which function produced which result. In this case something like this would work:
def callAll[A, B](funcs: List[PartialFunction[A, B]], a: A): List[B] = funcs.foldRight(List.empty[B])((f, acc) => if (f.isDefinedAt(a)) f.apply(a) :: acc else acc)
if order of elements is not important you may use
def callAll[A, B](funcs: List[PartialFunction[A, B]], a: A): List[B] = funcs.foldLeft(List.empty[B])((f, acc) => if (f.isDefinedAt(a)) f.apply(a) :: acc else acc)
which probably will be a bit faster
You want to get Option with Some in case corresponding function is defined at the point or None otherwise. In such case something like this would work:
def callAllOption[A, B](funcs: List[PartialFunction[A, B]], a: A): List[Option[B]] = funcs.map(f => f.lift.apply(a))
If you don't want to create List explicitly, you can use varargs such as:
def callAllOptionVarArg[A, B](a: A, funcs: PartialFunction[A, B]*): List[Option[B]] = funcs.map(f => f.lift.apply(a)).toList
or such curried version to specify value after functions:
def callAllOptionVarArg2[A, B](funcs: PartialFunction[A, B]*)(a: A): List[Option[B]] = funcs.map(f => f.lift.apply(a)).toList
You call functions purely for side effects and return value is not important, in which case you can safely use second (a bit faster) callAll definition
Examples:
val f: PartialFunction[Int, Int] = {
case 1 => 1
case 3 => 3
}
val g: PartialFunction[Int, Int] = {
case 2 => 2
case 3 => 4
}
val fl = List(f, g)
println(callAll(fl, 1))
println(callAll(fl, 3))
println(callAllOption(fl, 2))
println(callAllOptionVarArg(1, f, g))
println(callAllOptionVarArg2(f, g)(3))
List(1)
List(3, 4)
List(None, Some(2))
List(Some(1), None)
List(Some(3), Some(4))

directly applying lift function not give expected function

Below are the two partial function that are expected to perform sme tasks but defined in diffrent ways.
val pf1 : PartialFunction[String, String] = {
case s : String if (s != null) => s.toUpperCase()
}
//> pf1 : PartialFunction[String,String] = <function1>
val lift1 = pf1.lift
//> lift1 : String => Option[String] = <function1>
val d1 = lift1(null)
//> d1 : Option[String] = None
val d2 = lift1("hello world")
//> d2 : Option[String] = Some(hello world)
val pf2 = PartialFunction[String, String] {
case s : String if(s != null) => s.toUpperCase()
}
//> pf2 : PartialFunction[String,String] = <function1>
val lift2 = pf2.lift
//> lift2 : String => Option[String] = <function1>
val d3 = lift2(null)
//> scala.MatchError: null
val d4 = lift2("hii")
//> d4 : Option[String] = Some(hii)
Why passing null to lift2 gives MatchError, when the definition of both lift1 and lift2 is same?
If you look at PartialFunction.apply, you will see that it does a bit something different then what you've expected:
/** Converts ordinary function to partial one
* #since 2.10
*/
def apply[A, B](f: A => B): PartialFunction[A, B] = { case x => f(x) }
So it wraps a normal function into partial function that is defined on all domain. And that's why when you lift, you receive exception - because inside is still a normal not-lifted partial function, that is not defined
Why passing null to lift2 gives MatchError, when the definition of
both lift1 and lift2 is same?
They're not defined the same. When you define:
val pf1: PartialFunction[String, String] = {
case s : String if (s != null) => s.toUpperCase()
}
The compiler creates a PartialFunction, like this:
this.pf1 = ({
new <$anon: Function1>()
}: PartialFunction);
But when you declare pf2 like this:
val pf2 = PartialFunction[String, String] {
case s : String if(s != null) => s.toUpperCase()
}
You're actually telling the compiler "please take this Function1 and pass it to PartialFunction.apply. That is why the compiler does this:
this.pf2 = scala.PartialFunction.apply({
(new <$anon: Function1>(): Function1)
});
Which actually wraps a Function1 inside a partial function. So when you call pf2.lift(null), it will internally call the Function1, causing a MatchError as you're seeing.

pattern matching on function parameters in scala

Is it possible to pattern match on function heads in scala?
For example, can I write something along the lines of:
def myFunction(a:: b:: xs): Int = ???
def myFunction(a:: xs): Int = ???
def myFunction(List.empty): Int = ???
You can use partial functions for this case. Example:
val myFunctionCase1: PartialFunction[List[Int], Int] = {
case a :: b :: xs => ???
}
val myFunctionCase2: PartialFunction[List[Int], Int] = {
case a :: xs => ???
}
val myFunctionCase3: PartialFunction[List[Int], Int] = {
case Nil => ???
}
// compose functions
val myFunction: List[Int] => Int =
myFunctionCase1 orElse myFunctionCase2 orElse myFunctionCase3
Usage examples:
myFunctionCase1(List(1,2,3)) // invoke
myFunctionCase1(List(1)) // throw MatchError
myFunctionCase2(List(1)) // invoke
...
myFunction(List(1,2,3))
myFunction(List(1))
myFunction(Nil)
...

Match Error on List.collect

What's wrong with the second implementation?
Works:
scala> List(1,2,3).collect{ case i: Int if i % 2 == 0 => i }
res1: List[Int] = List(2)
Doesn't:
scala> val evens = PartialFunction[Any, Int]{
| case i: Int if i % 2 == 0 => i
| }
evens: PartialFunction[Any,Int] = <function1>
scala> List(1,2,3).collect{evens}
scala.MatchError: 1 (of class java.lang.Integer)
at $anonfun$1.apply(<console>:7)
at $anonfun$1.apply(<console>:7)
at scala.PartialFunction$$anonfun$apply$1.applyOrElse(PartialFunction.scala:242)
at scala.runtime.AbstractPartialFunction.apply(AbstractPartialFunction.scala:33)
at scala.collection.TraversableLike$$anonfun$collect$1.apply(TraversableLike.scala:278)
at scala.collection.immutable.List.foreach(List.scala:318)
...
You should create evens PartialFunction like this:
val evens: PartialFunction[Any, Int] = {
case i: Int if i % 2 == 0 => i
}
With PartialFunction[Any, Int]{ ... } you are calling an apply method of object PartialFunction. It defined like this:
def apply[A, B](f: (A) ⇒ B): PartialFunction[A, B]
So { case i: Int if i % 2 == 0 => i } is used as a function, not a PartialFunction and evens is defined at any argument:
scala> val evens = PartialFunction[Any, Int]{
| case i: Int if i % 2 == 0 => i
| }
scala> evens.isDefinedAt(1)
res1: Boolean = true
scala> val evens: PartialFunction[Any, Int] = {
| case i: Int if i % 2 == 0 => i
| }
scala> evens.isDefinedAt(1)
res5: Boolean = false
Your code actually does work on Scala 2.9.2 (modulo incorrect partial function declaration). However, in any case the reason is probably the type signature:
PartialFunction[Any, Int]
Since the first type parameter is Any, the collection elements get autoboxed to java.lang.Integer instances - it even says so in the stack trace (by necessity, since Any corresponds to Object). However, you're matching for Int, and this causes the error.
Using PartialFunction[Int, Int] should solve the problem, i.e.:
val evens:PartialFunction[Int, Int] = {case i: Int if i % 2 == 0 => i}