Partial functions

The possibility of having additional methods gives a way do define concepts that would be hard to state otherwise, at least without extending the language itself. One such example is partial functions. A partial function is a function that is undefined for some values of its arguments. The classical example is a division that is not defined, for the divider equals zero. But actually, it is possible to have arbitrary domain rules that make some function partial. For instance, we could decide that our string reverse function should be undefined for empty strings.

There are a couple of possibilities for implementing such constraints in a program:

  • Throw an exception for arguments for which the function is not defined
  • Constrain the type of an argument so that it is only possible to pass a valid argument to the function, for example using refined types
  • Reflect the partiality in the return type, for example using Option or Either

There are obvious tradeoffs related to each of these approaches and in Scala, the first one is preferred as most natural. But, to better model the partial nature of the function, there is a special trait available in the standard library: 

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

The key difference to normal function is that there is an additional method available that allows us to check whether the function is defined for some argument or not:

def isDefinedAt(x: A): Boolean

This allows the user of the function to do something different for "invalid" input values.

For example, let's imagine we've invented a very efficient method to check if a string is a palindrome. Then we could define our reverse function as two partial functions, one that is only defined for palindromes and does nothing and another that is defined only for non-palindromes and does the actual reverse action:

val doReverse: PartialFunction[String, String] = {
case str if !isPalindrome(str) => str.reverse
}
val noReverse: PartialFunction[String, String] = {
case str if isPalindrome(str) => str
}
def reverse = noReverse orElse doReverse

Here we're using syntactic sugar again to define our partial functions as a pattern match and compiler creates isDefinedAt method for us. Our two partial functions are combined into the total function using the orElse method.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.222.93.132