Anonymous PartialFunction syntax - scala

I asked this question earlier: Combine a PartialFunction with a regular function
and then realized, that I haven't actually asked it right.
So, here goes another attempt.
If I do this:
val foo = PartialFunction[Int, String] { case 1 => "foo" }
val bar = foo orElse { case x => x.toString }
it does not compile: error: missing parameter type for expanded function
The argument types of an anonymous function must be fully known. (SLS 8.5)
Expected type was: PartialFunction[?,?]
But this works fine:
val x: Seq[String] = List(1,2,3).collect { case x => x.toString }
The question is what is the difference? The type of the argument is the same in both cases: PartialFunction[Int, String]. The value passed in is literally identical. Why one does one case work, but not the other?

You need to specify the type for bar because the compiler is unable to infer it. This compiles:
val foo = PartialFunction[Int, String] { case 1 => "foo" }
val bar : (Int => String) = foo orElse { case x => x.toString }

In the case of List(1,2,3).collect{case x => x.toString} the compiler is able to infer the input type of the partial function based off of how theList was typed.
final override def collect[B, That](pf: PartialFunction[A, B])(implicit bf: CanBuildFrom[List[A], B, That])
Based on the type parameters the compiler can infer that you are passing a correctly typed partial function. That's why List(1,2,3).collect{case x:String => x.toString} does not compile nor does List(1,2,3).collect{case x:Int => x.toString; case x: String => x.toString}.
Since List is covariant the compiler is able to infer that the partial function {case x => x.toString} is a partial function on Int. You'll notice that List(1,2,3).collect{case x => x.length} does not compile because the compiler is inferring that you're operating on either an Int or a subclass of Int.
Also keep in mind that the {case x => x.toString} is just syntactic sugar. If we do something like the below then your example works as expected
val f = new PartialFunction[Int, String](){
override def isDefinedAt(x: Int): Boolean = true
override def apply(v1: Int): String = v1.toString
}
val foo = PartialFunction[Int, String] { case 1 => "foo" }
val bar = foo orElse f //This compiles fine.
List(1,2,3).collect{f} // This works as well.
So the only logical answer from my perspective is that the syntactic sugar that is able to generate a PartialFunction instance for {case x => x.toString} does not have enough information at compile time to be able to adequately type it as a PartialFunction[Int, String] in your orElse case.

You can use the library Extractor.scala.
import com.thoughtworks.Extractor._
// Define a PartialFunction
val pf: PartialFunction[Int, String] = {
case 1 => "matched by PartialFunction"
}
// Define an optional function
val f: Int => Option[String] = { i =>
if (i == 2) {
Some("matched by optional function")
} else {
None
}
}
// Convert an optional function to a PartialFunction
val pf2: PartialFunction[Int, String] = f.unlift
util.Random.nextInt(4) match {
case pf.extract(m) => // Convert a PartialFunction to a pattern
println(m)
case f.extract(m) => // Convert an optional function to a pattern
println(m)
case pf2.extract(m) => // Convert a PartialFunction to a pattern
throw new AssertionError("This case should never occur because it has the same condition as `f.extract`.")
case _ =>
println("Not matched")
}

Related

Scala: match case over generic functions

Is it possible to do match-case over functions?
I want to define a behavior for different types of functions. Say I have the following possibilities:
f: T => Int
f: T => String
f: T => Lis[Int]
f: T => Boolean
f: T => Double
...
and for each of these options I have a function; for example for Int output:
def doThisForInt(f: T => Int) = { ... }
and this for Boolean output:
`
def doThisForBoolean(f: T => Boolean) = { ... }
So now suppose a function definition is given: val f = (input: T) => true. We should choose the corresponding case to f: T => Boolean.
Note that all these functions differ in the output type. Alternatively, given f can I get the output type of this function?
TypeTags are what you are looking for:
import scala.reflect.runtime.universe._
def doThisForInt(f: T => Int) = ???
def printType[R: TypeTag](f: T => R) = typeOf[R] match {
case t if t =:= typeOf[Int] =>
val toInt: (T) => Int = f.asInstanceOf[T => Int]
doThisForInt(toInt)
case t if t =:= typeOf[Double] =>
// ...
case t if t =:= typeOf[List[Int]] =>
// ...
}
printType((x: T) => 1) // int
printType((x: T) => 2.0) // double
printType((x: T) => List(2)) // list
As you can see, it is possible, but not very elegant and against good practices.
Chains of instanceOf checks can often be replaced with virtual methods (see the example) and the result type of function can possibly be a type parameter. It's hard to give more advice without knowing more context for your use case.

Return type eliminated by erasure in Scala

Consider the following Scala code snippet:
def func(param: Any): Int = param match {
case f: (String => Int) => f("apple")
case i: Int => i
}
println(func((s: String) => s.length))
Works as expected, however, at compilation I get the following warning:
<console>:11: warning: non-variable type argument String in type pattern String => Int is unchecked since it is eliminated by erasure
case f: (String => Int) => f("apple")
How can I get rid of this warning message?
Thanks your help in advance!
The reason why you get the message is because of Java's generic type erasure. In this particular case, your function which is of type Function[String, Int] will be matched by any Function[A, B].
In order to get rid of this warning you should use scala typetags which will allow you to differentiate between the different function types.
The code snippet is below,
import scala.reflect.runtime.universe._
object Answer {
def function[A](param: A)(implicit tt: TypeTag[A]): String = param match {
case f: (String => Int) #unchecked if typeOf[String => Int] =:= typeOf[A] => f("apple").toString
case f: (Int => String) #unchecked if typeOf[Int => String] =:= typeOf[A] => f(32 + 1)
case s: String => s"hello $s"
}
def main (args: Array[String]) {
println(function((s: String) => s.length))
println(function((i: Int) => i.toString))
println(function("world"))
}
}
The key part is to have an implicit TypeTag[A] which is added at compile time which includes the metadata that the function typeOf needs to check the types of A against anything else.

Scala Multiple Inheritance: Differentiate between Iterable and PartialFunction in method arguments

I want to be able to define a method with the same name that has a different implementation if the argument is an Iterable[T1] vs a function: T1 => T2
However, many classes that implement Iterable also implement PartialFunction
For example:
object FunList {
def foo(itr: Iterable[Int]) = println("hello")
def foo(f: (Int => Int)) = println("Goodbye")
}
scala> FunList.foo(List(1))
<console>:9: error: ambiguous reference to overloaded definition,
both method foo in object FunList of type (f: Int => Int)Unit
and method foo in object FunList of type (itr: Iterable[Int])Unit
match argument types (List[Int])
FunList.foo(List(1))
currently my solution looks like this, but it does not match subclasses of Iterable which are not also subclasses of PartialFunction
case class SeqOrFun[T1, T2](f: (T1 => T2))
implicit def seqOrFun[T1, T2](f: (T1 => T2)) = SeqOrFun(f)
def unfurl[T1: Numeric, T2: Numeric](x: SeqOrFun[T1, T2], y: SeqOrFun[T1, T2]) = {
(x.f, y.f) match {
case (xs: Iterable[T1], ys: Iterable[T2]) => (xs, ys)
case (xf: (T2 => T1), ys: Iterable[T2]) => (ys.map(xf), ys)
case (xs: Iterable[T1], yf: (T1 => T2)) => (xs, xs.map(yf))
}
}
Since List is both Iterable[Int] and Int => Int, as you've said, what you're writing is inherently abmiguous. Perhaps I've misread, but I don't see any place at all where you've specified whether you want FunList.foo(List(1)) to print "hello" or "Goodbye".
First, you can use a cast at the call site. I assume you already know this, but just to be explicit for the sake of discussion:
FunList.foo(List(1): Int => Int) // "hello"
FunList.foo(List(1): Iterable[Int]) // "Goodbye"
If our objective here is to allow the caller to simply write FunList.foo(List(1)), you could use the magnet pattern. This means you don't use method overloading at all; instead you write a single method, and the dispatch is done with implicit conversions.
sealed trait FooMagnet
case class HelloMagnet(itr: Iterable[Int]) extends FooMagnet
case class GoodbyeMagnet(f: Int => Int) extends FooMagnet
def foo(x: FooMagnet): Unit = x match {
case HelloMagnet(itr) => println("hello")
case GoodbyeMagnet(f) => println("Goodbye")
}
def a(): Unit = {
implicit def listIsHelloMagnet(x: List[Int]): FooMagnet = HelloMagnet(x)
FunList.foo(List(1)) // "hello"
}
def b(): Unit = {
implicit def listIsGoodbyeMagnet(x: List[Int]): FooMagnet = GoodbyeMagnet(x)
FunList.foo(List(1)) // "Goodbye"
}
The fun advantage you get here is that the dispatch decision is decoupled from the foo implementation, since it's determined by those implicits which you can define wherever you like.
You can also use this to resolve the ambiguity problem! Start with the two implicits from earlier:
implicit def iterableIsHelloMagnet(x: Iterable[Int]): FooMagnet = HelloMagnet(x)
implicit def functionIsGoodbyeMagnet(x: Int => Int): FooMagnet = GoodbyeMagnet(x)
And then add another implicit specifically for List[Int].
implicit def listIsHelloMagnet(x: List[Int]): FooMagnet = HelloMagnet(x)
Scala is clever enough to see that this third conversion is more specific than the first two, so it will use that one for List[Int] even though they all apply. Thus we can now write:
FunList.foo(Set(1)) // "hello"
FunList.foo((_: Int) + 1) // "Goodbye"
FunList.foo(List(1)) // "hello"
And you can move the definitions of those implicits into the called library, so all the caller has to do is import them.

How does orElse work on PartialFunctions

I am getting very bizarre behavior (at least it seems to me) with the orElse method defined on PartialFunction
It would seem to me that:
val a = PartialFunction[String, Unit] {
case "hello" => println("Bye")
}
val b: PartialFunction[Any, Unit] = a.orElse(PartialFunction.empty[Any, Unit])
a("hello") // "Bye"
a("bogus") // MatchError
b("bogus") // Nothing
b(true) // Nothing
makes sense but this is not how it is behaving and I am having a lot of trouble understanding why as the types signatures seem to indicate what I exposed above.
Here is a transcript of what I am observing with Scala 2.11.2:
Welcome to Scala version 2.11.2 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_11).
Type in expressions to have them evaluated.
Type :help for more information.
scala> val a = PartialFunction[String, Unit] {
| case "hello" => println("Bye")
| }
a: PartialFunction[String,Unit] = <function1>
scala> a("hello")
Bye
scala> a("bye")
scala.MatchError: bye (of class java.lang.String)
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:36)
... 33 elided
scala> val b = a.orElse(PartialFunction.empty[Any, Unit])
b: PartialFunction[String,Unit] = <function1>
scala> b("sdf")
scala.MatchError: sdf (of class java.lang.String)
at $anonfun$1.apply(<console>:7)
at $anonfun$1.apply(<console>:7)
at scala.PartialFunction$$anonfun$apply$1.applyOrElse(PartialFunction.scala:242)
at scala.PartialFunction$OrElse.apply(PartialFunction.scala:162)
... 33 elided
Note the return type of val b which has not widen the type of the PartialFunction.
But this also does not work as expected:
scala> val c = a.orElse(PartialFunction.empty[String, Unit])
c: PartialFunction[String,Unit] = <function1>
scala> c("sdfsdf")
scala.MatchError: sdfsdf (of class java.lang.String)
at $anonfun$1.apply(<console>:7)
at $anonfun$1.apply(<console>:7)
at scala.PartialFunction$$anonfun$apply$1.applyOrElse(PartialFunction.scala:242)
at scala.PartialFunction$OrElse.apply(PartialFunction.scala:162)
... 33 elided
There's a few things wrong with your attempt, but first let's see a working implementation:
scala> val a: PartialFunction[String, Unit] = { case "hello" => println("bye") }
a: PartialFunction[String,Unit] = <function1>
scala> val b: PartialFunction[Any, Unit] = { case _ => println("fallback") }
b: PartialFunction[Any,Unit] = <function1>
scala> val c = a.orElse(b)
c: PartialFunction[String,Unit] = <function1>
scala> c("hello")
bye
scala> c("foo")
fallback
There's two main errors in your code:
the way the PF is defined
the (wrong) assumption that empty is a "catch-all" function that returns Nothing
1. How to define a PartialFunction
val right: PartialFunction[String, Unit] = {
case "hello" => println("bye")
}
How not to define it:
val wrong = PartialFunction[String, Unit] {
case "hello" => println("bye")
}
If you look at the definition of PartialFunction.apply
def apply[A, B](f: A => B): PartialFunction[A, B] = { case x => f(x) }
you'll see that it defines a partial function for any x and it applies the given f function to it. Now your { case "hello" => println("bye") } is the f argument, so you approximately end up with the following (clearly unexpected) PartialFunction:
val wrong: PartialFunction[String, Unit] = {
case x => x match {
case "hello" => println("bye")
}
So when you ask whether it's defined it will always return true, since it's defined for any string:
wrong.isDefinedAt("hello") // true (ok)
wrong.isDefinedAt("whatever") // true (sure?)
but when you try to apply it
wrong("hello") // bye (ok)
wrong("whatever") // MatchError (BOOM!)
you fall short on the inner match.
Since orElse decides whether to call the "else" depending on the result of isDefined, then it's obvious why it fails.
2. Empty catches nothing!
Straight from the docs:
def empty[A, B]: PartialFunction[A, B]
The partial function with empty domain. Any attempt to invoke empty partial function leads to throwing scala.MatchError exception.
The PartialFunction (well, it's not really partial anymore) you're looking for is:
val fallback: PartialFunction[Any, Unit] = { case _ => println("fallback") }
or - just to show that we learn from our mistakes -
val fallback = PartialFunction[Any, Unit] { _ => println("fallback") }
You are using the PartialFunction object apply method which is defined so:
def apply[A, B](f: A => B): PartialFunction[A, B] = { case x => f(x) }
Basically it takes a function form A to B and automatically wrap it in a case statement, the problem is that you are passing the case too and I'm not 100% sure of what happens then, you can try passing a function to the apply or easily you can try without using the apply method:
scala> val a: PartialFunction[String, Unit] = {
| case "hello" => println("Bye")
| }
a: PartialFunction[String,Unit] = <function1>
scala> val b: PartialFunction[String, Unit] = {
| case _ => println("default")
| }
b: PartialFunction[String,Unit] = <function1>
scala> b("123")
default
You could also extend the trait and implement apply and isDefined as shown here.
PartialFunction.empty[A,B] is equivalent to:
{
case x: Nothing => x
}
(This typechecks, because Nothing is a subtype of both A and B.)
or, equivalently:
{
// note: this is probably not a valid Scala code for a partial function
// but, as PartialFunction.empty's name suggests, it's an *empty* block
}
This cannot match anything.
.orElse can be understood to simply concatenates lists of case statements from two PartialFunctions. So, in your case a.orElse(PartialFunction.empty[Any,Unit] means:
{ case "hello" => println("Bye") } orElse { /* no cases here */ }
which simplifies to:
{ case "hello" => println("Bye") }
or
{ case "hello" => println("Bye"); case x:Nothing => x }
MatchError is therefore obvious.
Note that the documetation also mentions that empty always throws MatchError.
From what I can guess, you wanted a PartialFunction that always matches. There's no named method in the standard library for that, but why should there be. You can simply write
{ case _ => () }

Why is PartialFunction <: Function in Scala?

In Scala, the PartialFunction[A, B] class is derived from type Function[A, B] (see Scala Reference, 12.3.3). However, this seems counterintuitive to me, since a Function (which needs to be defined for all A) has more stringent requirements than a PartialFunction, which can be undefined at some places.
The problem I've come across is that when I have a partial function, I cannot use a Function to extend the partial function. Eg. I cannot do:
(pf orElse (_)=>"default")(x)
(Hope the syntax is at least remotely right)
Why is this subtyping done reversely? Are there any reasons that I've overlooked, like the fact that the Function types are built-in?
BTW, it would be also nice if Function1 :> Function0 so I needn't have the dummy argument in the example above :-)
Edit to clarify the subtyping problem
The difference between the two approaches can be emphasized by looking at two examples. Which of them is right?
One:
val zeroOne : PartialFunction[Float, Float] = { case 0 => 1 }
val sinc = zeroOne orElse ((x) => sin(x)/x) // should this be a breach of promise?
Two:
def foo(f : (Int)=>Int) {
print(f(1))
}
val bar = new PartialFunction[Int, Int] {
def apply(x : Int) = x/2
def isDefinedAt(x : Int) = x%2 == 0
}
foo(bar) // should this be a breach of promise?
Because in Scala (as in any Turing complete language) there is no guarantee that a Function is total.
val f = {x : Int => 1 / x}
That function is not defined at 0. A PartialFunction is just a Function that promises to tell you where it's not defined. Still, Scala makes it easy enough to do what you want
def func2Partial[A,R](f : A => R) : PartialFunction[A,R] = {case x => f(x)}
val pf : PartialFunction[Int, String] = {case 1 => "one"}
val g = pf orElse func2Partial{_ : Int => "default"}
scala> g(1)
res0: String = one
scala> g(2)
res1: String = default
If you prefer, you can make func2Partial implicit.
PartialFunction has methods which Function1 does not, therefore it is the subtype. Those methods are isDefinedAt and orElse.
Your real problem is that PartialFunctions are not inferred sometimes when you'd really like them to be. I'm hopeful that will be addressed at some future date. For instance this doesn't work:
scala> val pf: PartialFunction[String, String] = { case "a" => "foo" }
pf: PartialFunction[String,String] = <function>
scala> pf orElse { case x => "default" }
<console>:6: error: missing parameter type for expanded function
((x0$1) => x0$1 match { case (x # _) => "default" })
But this does:
scala> pf orElse ({ case x => "default" } : PartialFunction[String,String])
res5: PartialFunction[String,String] = <function>
Of course you could always do this:
scala> implicit def f2pf[T,R](f: Function1[T,R]): PartialFunction[T,R] =
new PartialFunction[T,R] {
def apply(x: T) = f(x)
def isDefinedAt(x: T) = true
}
f2pf: [T,R](f: (T) => R)PartialFunction[T,R]
And now it's more like you want:
scala> pf orElse ((x: String) => "default")
res7: PartialFunction[String,String] = <function>
scala> println(res7("a") + " " + res7("quux"))
foo default