Skip to content

Instantly share code, notes, and snippets.

@nicerobot
Last active October 11, 2015 20:10
Show Gist options
  • Select an option

  • Save nicerobot/4be49f572cecea1da0df to your computer and use it in GitHub Desktop.

Select an option

Save nicerobot/4be49f572cecea1da0df to your computer and use it in GitHub Desktop.
Scala PartialFunction and Partially-applied functions

Partial functions are largely about function composition. Specifically, being able to compose different parts of a function, then either call a fully defined function or handle the possibility of an undefined value.

Note: Partially-applied functions and partial functions are similar in that they are functions.

  • partially-applied functions encapsulate partial functionality.
  • partial functions describe partial functionality.

While I've seen plenty of comments stating partial application is not related to partial functions. I somewhat disagree. A specific partial application can be thought of as a restructured implementation of partial functions. Another way to think of it is that partial application ensures that a particular input of a partial function execution is defined for the input.

1. Success(0.2)
1. Failure(scala.MatchError: 0 (of class java.lang.Integer))
1. Failure(scala.MatchError: (of class java.lang.String))
2. Success(0.2)
2. Success(NaN)
2. Success(NaN)
3. Success(0.2)
3. Success(NaN)
3. Success(NaN)
import scala.util.Try
// A Partial Function can be thought of in two ways:
object Main extends App {
// 1. The literal meaning is that the function is _not_ defined for all inputs.
// Notice how `g` is describing the properties of the function for _part_
// of the input domain.
def g: PartialFunction[Any, Double] = {
case i: Int if i != 0 => 2.0 / i.toDouble
}
printf("1. %s\n", Try(g(10)))
printf("1. %s\n", Try(g(0)))
printf("1. %s\n", Try(g("")))
// Ignore this for a second.
def defaulted(d: Double): PartialFunction[Any, Double] = {
case _ => d
}
// 2. An implied meaning is that, eventually, a function is intended to be fully
// defined elsewhere. In fact, the only way to apply a partial function is to
// also, somehow, handle the complete domain of inputs (albeit, even meaning
// propagation of a MatchError exiting the JVM).
def f(x: Any, otherwise: Double = Double.NaN): Double =
g.orElse[Any,Double](defaulted(otherwise))(x)
printf("2. %s\n", Try(f(10)))
printf("2. %s\n", Try(f(0)))
printf("2. %s\n", Try(f("")))
// 3. Partial application
def h(otherwise: Double)(x: Any) = x match {
case i: Int if i != 0 => 2.0 / i.toDouble
case _ => otherwise
}
// Both `i` and `h` are fully defined functions. `i` simply encapsulates a
// particular flow, as if it were processing a subset of the input domain.
def i: Any => Double = h(Double.NaN)
printf("3. %s\n", Try(i(10)))
printf("3. %s\n", Try(i(0)))
printf("3. %s\n", Try(i("")))
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment