Partial functions in Scala
By: Deepak Kumar
Tags: Programming, Scala, Partialfunctions, Scala Programming

According to mathematical definition a function which is defined for some range of a domain and not defined for some other range of the same domain is called a partial function.

A simple example would be division of a number by an integer ‘x’.

f(x) = N/x

Here you know that division by ‘0’ is not possible therefore the domain of ‘f’ does not include the integer ‘0’.

Similarly any function that applies only to a subset of a domain can be represented as a partial function. Scala standard library provides us with a trait PartialFunction which is of the following signature. This trait allows us to define partial functions which takes a single parameter.

trait PartialFunction[-A, +B] extends (A) => B

The signature implies it is a function that takes a single parameter of contravarient nature (ie, a subtype of A be given as input) and returns something of covarient nature (ie, a super type of B could be returned as output)

From the Scala standard library documentation

A partial function of type PartialFunction[A, B] is a unary function where the domain does not necessarily include all values of type A. The function isDefinedAt allows to test dynamically if a value is in the domain of the function.

Lets take an example of a set of weekdays, we have seven weekdays but how do you represent them? Well you could represent them as a subset of strings containing only seven strings. Then if we have a function that accepts a string and returns the day of the week as a an integer is going to be a partial function by definition.

def getDay(day: String): Int = day match {

case "sunday" => 1

case "monday" => 2

case "tuesday" => 3

case "wednesday" => 4

case "thursday" => 5

case "friday" => 6

case "saturday" => 7

}



getDay("monday") // res10: Int = 2

getDay("someday") // scala.MatchError: ...

The above method does what we wanted, but Scala provides a verbose way by which we can represent it as a partial function.

def getDay: PartialFunction[String, Int] = {

case "sunday" => 1

case "monday" => 2

case "tuesday" => 3

case "wednesday" => 4

case "thursday" => 5

case "friday" => 6

case "saturday" => 7

}



getDay("monday")

getDay("someday") // scala.MatchError: ...

Another representation would be using ADT we could create a set of all weekdays. If the domain is defined and all the members are handled then it becomes a total function.

sealed trait Weekday

case object Sunday extends Weekday

case object Monday extends Weekday

case object Tuesday extends Weekday

case object Wednesday extends Weekday

case object Thursday extends Weekday

case object Friday extends Weekday

case object Saturday extends Weekday



def getDay: PartialFunction[Weekday, Int] = {

case Sunday => 1

case Monday => 2

case Tuesday => 3

case Wednesday => 4

case Thursday => 5

case Friday => 6

case Saturday => 7

} getDay(Sunday)

getDay(Someday) // does not compile

But the problem here is we have converted this to a total function, so it is theoretically incorrect to define it using trait PartialFunction. This could be better written as a total function as follows.

val getDay: Weekday => Int = (weekday) => weekday match {

case Sunday => 1

case Monday => 2

case Tuesday => 3

case Wednesday => 4

case Thursday => 5

case Friday => 6

case Saturday => 7

} getDay(Sunday)

As you can see in the above approach the the codes doesn’t even compile, the type check fails which is a great thing when it comes to correctness of the program.

But in general partial functions are very useful in day to day programming because we don’t always prefer creating a domain and converting that to a total function. We mostly prefer to work with basic types or derived types instead of defining ADT for the whole domain, but if the overhead of defining an ADT makes sense then it should be done.