Higher Order Function
In the earlier section, I explained pure functions. Higher Order function is
another concept closely associated with the
first class functions. You can define a Higher Order function as given below.
A function that does at least one of the following is a Higher Order Function.
- Takes one or more functions as arguments
- Returns a function as its result
Let's assume I have a function F1. By default, F1 is a
first-class
function. So I should be able to pass F1 to another function. Now, let's
assume
I have another function F2. If we design F2 in a way that it can
take
F1 as an argument, the F2 is a higher order function. That is
what
the definition says.
Now, let's look at a working example for both types of Higer Order Functions.
Scala function that takes another function as argument
The first and second line of the above code defines two Scala functions. The third line defines a higher order function. The function applyF takes two arguments. First argument type is a function and the second argument is an integer. The next line passes doubler function to applyF. Similarly, the last line also passes a tripler function to applyF.
Scala function that returns another function
The code shown above defines a function getOps. The first line inside the body of the getOps defines a local function doubler. The second line defines another local function tripler. Finally, the if expression returns an appropriate local function depending on the value of c. Later, we call the getOps function and assign the returned value to d. The variable d holds a function that we call as the last line. We have seen both types of Higher Order functions.
Why Higher Order Functions?
We can pass functions and return them. However, you might be wondering about the benefits. What is the purpose of all this? I am more than happy to use Object Oriented techniques. What is so great about the notion of passing around functions?
Abstraction
Abstraction is the main benefit of Higher Order functions. Abstraction makes the
application easily extendable. When developing
with a higher level of abstraction, you communicate the behavior and less the
implementation.
Let's try to understand it with a simple example.
Let's say you have an array of customers.
Now you want to send a greeting message to all of these clients. The most obvious method to do it is a loop. It may be something like this.
It's a quite simple code. For each customer, we want to call a function println. Instead of println, you may have some other function. For example payment reminder.
The above code is a dummy function for payment reminder. The new loop looks as below.
So, what are we doing? In fact, we want to say this.
For each customer, remind payment
If you design the above scenario using a higher order function. Your final code
should
look like this.
This line does the same thing. However, I have abstracted the implementation details behind a higher order function. The forEach is a higher order function, and it takes two parameters. This type of programming approach is more precise, easy to understand and more reusable. I can reuse the same function to send payment to all my vendors.
The below code shows a simple method to implement the forEach function.
The forEach function takes two parameters. The first parameter is an array of strings. The second parameter is a function. We loop through the array and call the function. In fact, Scala provides this kind of iterator method for every collection. So you do not need to implement a forEach function.
The above line is using Scala's built in foreach.
It says - take
customers,
and for each customer, remind payment.
Keep reading for more interesting functional concepts.
Read More
Pure Functions | Referential Transparency | Benefits of pure functions | First class functions | Higher order function | Anonymous functions | Immutability | Tail Recursion | Expressions in Scala | Lazy Evaluations | Pattern Matching | Closures