What is the difference between anonymous functions and partial functions?

704 Views Asked by At

I was reading about scala anonymous functions here and saw that they can take the format:

{ case p1 => b1 … case pn => bn }

However, I thought that this was how partial functions were written. In fact, in this blog post, the author calls a partial function an anonymous function. At first he says that collect takes a partial function but then appears to call it an anonymous function ("collect can handle the fact that your anonymous function...").

Is it just that some anonymous functions are partial functions? If so, are all partial functions anonymous? Or are they only anonymous if in format like Alvin Alexander's example here:

val divide2: PartialFunction[Int, Int] = {
    case d: Int if d != 0 => 42 / d
}
3

There are 3 best solutions below

0
username On BEST ANSWER

From the documentation on pattern matching anonymous functions that you linked:

If the expected type is SAM-convertible to scala.Functionk[S1,…,Sk, R], the expression is taken to be equivalent to the anonymous function:

(x1:S1,…,xk:Sk) => (x1,…,xk) match {   
    case p1 => b1 … case pn => bn 
}

Here, each xi is a fresh name. As was shown here, this anonymous function is in turn equivalent to the following instance creation expression, where T is the weak least upper bound of the types of all bi.

new scala.Functionk[S1,…,Sk, T] {   
  def apply(x1:S1,…,xk:Sk): T = (x1,…,xk) match {
    case p1 => b1 … 
    case pn => bn   
  } 
} 

If the expected type is scala.PartialFunction[S, R], the expression is taken to be equivalent to the following instance creation expression:

new scala.PartialFunction[S, T] {   
  def apply(x: S): T = x match {
    case p1 => b1 … case pn => bn   
  }   
  def isDefinedAt(x: S): Boolean = {
    case p1 => true … case pn => true
    case _ => false   
  } 
}

Your first code snippet is a pattern matching anonymous function, but not necessarily a partial function. It would only be turned into a PartialFunction if it was given to a method with a PartialFunction parameter or assigned to a variable of type PartialFunction.

So you are right that just some (pattern matching) anonymous functions are partial functions (AFAIK, function literals defined with fat arrows, such as x => x, can only ever be used to create FunctionN instances and not PartialFunction instances).

However, not all partial functions are anonymous functions. A sugar-free way to define PartialFunctions is extending the PartialFunction trait (which extends Function1) and manually overriding the isDefinedAt and apply methods. For example, divide2 could also be defined like this, with an anonymous class:

val divide2 = new PartialFunction[Int, Int] {
  override def isDefinedAt(x: Int) = x != 0
  override def apply(x: Int) = 42 / x
}

You probably won't see this very often, though, as it's a lot easier to just use pattern matching to define a PartialFunction.


In the blog post by Alvin Alexander you linked, the author refers to the pattern matching anonymous partial function literal as an anonymous function only because it happens to be both a partial function and an anonymous function. You could also define the function like so:


List(42, "cat").collect(new PartialFunction[Any, Int] {
  def isDefinedAt(x: Any) = x.isInstanceOf[Int]
  def apply(x: Any) = x match {
    case i: Int => i + 1
  }
})

It's no longer an anonymous function, although it's still an anonymous object that's the instance of an anonymous class. Or you could define a singleton object beforehand and then use that.

object Foo extends PartialFunction[Any, Int] {
  def isDefinedAt(x: Any) = x.isInstanceOf[Int]
  def apply(x: Any) = x match {
    case i: Int => i + 1
  }
}
List(42, "cat").collect(Foo)

No matter how you define it, though, it's a partial function.

3
Yann Hoffmann On

Here's another way of writing your pattern matching partial function.

val divide = new PartialFunction[Int, Int] {
    def apply(x: Int) = 42 / x
    def isDefinedAt(x: Int) = x != 0
}

In essence, a partial function is a function that isn't defined for a set of inputs. It could be like in the example that it doesn't make sense to divide by 0, or you could want to restrict some specific values.

The nifty thing with partial functions is that it has synergies with orElse, andThen and collect. Depending on whether or not you're inputing a 0 in the divide function, your variable can be passed along to andThen if it wasn't a 0, can go through orElse if it was a 0. Finally, collect will only apply your partial function if it is defined on that input.

The way you create a partial function is usually through pattern matching with case as shown in your example.

Last thing, an anonymous function in Scala is like a lambda in Python. It's just a way of creating a function without "naming" it.

Eg

val f: Int => Int = (x: Int) => x * x
collect {
    case a: Int => 1-a
}
0
Mario Galic On

Anonymous and partial are different concepts. We would not say the following function is anonymous

val divide2: PartialFunction[Int, Int] = {
    case d: Int if d != 0 => 42 / d
}

because it is bound to the name divide2, however we could say divide2 is defined in terms of the anonymous (function) value

{ case d: Int if d != 0 => 42 / d }

in the same sense x is defined in terms of anonymous value 42 in the following definition

val x: Int = 42

Orthogonal concept of partial refers to special subtype of function, as opposed to whether values of particular type are bound to a name or not.