Introduction
Functional programming (FP) is a programming style that emphasises the use of referentially transparent pure functions and immutable data structures. Higher order functions (HOFs) tend to be used extensively to enable a clean functional programming style. A HOF is just a function that either takes a function as an argument or returns a function. For example, the default List type in Scala is immutable. So, if one defines a list via
val l1 = List(1,2,3)
we add a new value to the front of the list by creating a new list from the old list and leaving the old list unchanged:
val l2 = 4 :: l1 // List(4, 1, 2, 3)
We can create a new list the same length as an existing list by applying the same function to each element of the list in turn using map:
val l3 = l2 map { x => x*x } // List(16, 1, 4, 9)
We could write this slightly differently as
val l4 = l2.map(x => x*x)
which makes it clearer that map is a higher order function on lists. In fact, the presence of a map method on List[_] makes it a functor, but that is a topic for another post.
HOFs are ubiquitous in FP, and very powerful. But there are a few techniques for working with functions in Scala (and other FP languages) which make creating and using HOFs more convenient.
Plotting a function of one scalar variable
There are many, many reasons for using functions and HOFs in scientific and statistical computing (optimising, integrating, differentiating, or sampling, to name just a few). But the basic idea can be illustrated simply by considering the problem of plotting a function of one scalar variable.
All of the code associated with this post is available in the curry directory of my blog repo. Full instructions for running the code are included in the README. The code includes a simple short method, plotFun which uses breeze to produce a simple plot of a user supplied function. For example:
import Currying._ plotFun(x => x*x)
produces the plot:
We can use this method to plot other functions, for example:
def myQuad1(x: Double): Double = x*x - 2*x + 1 plotFun(myQuad1) def myQuad2(x: Double): Double = x*x - 3*x - 1 plotFun(myQuad2)
Now technically, myQuad1 and myQuad2 are methods rather than functions. The distinction is a bit subtle, and they can often be used interchangeably, but the difference does sometimes matter, so it is good to understand it. To actually define a function and plot it, we could instead use code like:
val myQuad3: (Double => Double) = x => -x*x + 2 plotFun(myQuad3)
Note that here myQuad3 is a value whose type is a function mapping a Double to a Double. This is a proper function. This style of function declaration should make sense to people coming from other functional languages such as Haskell, but is potentially confusing to those coming from O-O languages such as Java. Note that is is easy to convert a method to a function using an underscore, so that, for example, myQuad2 _ will give the function corresponding to myQuad2. Note that there is no corresponding way to get a method from a function, so that is one reason for preferring method declaration syntax (and there are others, such as the ability to parametrise method declarations with generic types).
Now, rather than defining lots of specific instances of quadratic functions from scratch, it would make more sense to define a generic quadratic function and then just plot particular instances of this generic quadratic. It is simple enough to define a generic quadratic with:
def quadratic(a: Double, b: Double, c: Double, x: Double): Double = a*x*x + b*x + c
But we clearly can’t pass that in to the plotting function directly, as it has the wrong type signature (not Double => Double), and the specific values of a, b and c need to be given. This issue crops up a lot in scientific and statistical computing – there is a function which has some additional parameters which need to be fixed before the function can actually be used. This is referred to as the “function environment problem” by Oliveira and Stewart (section 8.5). Fortunately, in functional languages it’s easy enough to use this function to create a new “partially specified” function and pass that in. For example, we could just do
plotFun(x => quadratic(3,2,1,x))
We can define another function, quadFun, which allows us to construct these partially applied function closures, and use it as follows:
def quadFun(a: Double, b: Double, c: Double): Double => Double = x => quadratic(a,b,c,x) val myQuad4 = quadFun(2,1,3) plotFun(myQuad4) plotFun(quadFun(1,2,3))
Here, quadFun is a HOF in the sense that it returns a function closure corresponding to the partially applied quadratic function. The returned function has the type Double => Double, so we can use it wherever a function with this signature is expected. Note that the function carries around with it its lexical “environment”, specifically, the values of a, b and c specified at the time quadFun was called. This style of constructing closures works in most lexically scoped languages which have functions as first class objects. I use this style of programming a lot in several different languages. In particular, I’ve written previously about lexical scope and function closures in R.
Again, the intention is perhaps slightly more explicit if we re-write the above using function syntax as:
val quadFunF: (Double,Double,Double) => Double => Double = (a,b,c) => x => quadratic(a,b,c,x) val myQuad5 = quadFunF(-1,1,2) plotFun(myQuad5) plotFun(quadFunF(1,-2,3))
Now, this concept of partial application is so prevalent in FP that some languages have special syntactic support for it. In Scala, we can partially apply using an underscore to represent unapplied parameters as:
val myQuad6 = quadratic(1,2,3,_: Double) plotFun(myQuad6)
In Scala we can also directly write our functions in curried form, with parameters (or parameter lists) ordered as they are to be applied. So, for this example, we could define (partially) curried quad and use it with:
def quad(a: Double, b: Double, c: Double)(x: Double): Double = a*x*x + b*x + c plotFun(quad(1,2,-3)) val myQuad7 = quad(1,0,1) _ plotFun(myQuad7)
Note the use of an underscore to convert a partially applied method to a function. Also note that every function has a method curried which turns an uncurried function into a (fully) curried function. So in the case of our quadratic function, the fully curried version will be a chain of four functions.
def quadCurried = (quadratic _).curried plotFun(quadCurried(1)(2)(3))
Again, note the strategic use of an underscore. The underscore isn’t necessary if we have a true function to start with, as the following illustrates:
val quadraticF: (Double,Double,Double,Double) => Double = (a,b,c,x) => a*x*x + b*x + c def quadCurried2 = quadraticF.curried plotFun(quadCurried2(-1)(2)(3))
Summary
Working with functions, closures, HOFs and partial application is fundamental to effective functional programming style. Currying functions is one approach to handling the function environment problem, and is the standard approach in languages such as Haskell. However, in Scala there are other possible approaches, such as using underscores for partial application. The preferred approach will depend on the context. Currying is often used for HOFs accepting a function as argument (as it can help with type inference), and also in conjunction with implicits (beyond the scope of this post – pun intended). In other contexts partial application using underscores seems to be more commonly used.
References
- Oliveira, S, Stewart, D.E. (2006) Writing scientific software, CUP.
- Horstmann, C. S. (2012) Scala for the impatient, Addison Wesley.
- Chiusano, P., Bjarnason, R. (2014) Functional programming in Scala, Manning