Question

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 came accross was 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?

No correct solution

OTHER TIPS

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
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top