Think Functional with Filter, Map and Reduce
Hello functional programming beginners. I am going to walk you through three of the most common higher order functions that would help you kick your functional programming confidence into high gear.
But on that same note, if your language of choice does allow passing of functions as variables, it doesn’t mean that the programs would be efficient because in some cases the compiler cannot optimize the code. For example, if you were to use higher order functions in PHP, since PHP is primarily object oriented, it would create objects on the fly. In most cases the performance impact is reasonable, and this is just a caveat.
Alright, now before we discuss what filter, map and reduce do, let’s look at what they are generally. These types of functions are called Higher-Order Functions. That is just a fancy way of saying that these functions could take other functions as parameters.
While learning your first programming language, you would have heard of basic data types. There are usually some basic data types that are supported out of the box like integers and strings, even lists and arrays in more high level programming languages. In languages that support the functional paradigm, functions are also treated as basic data types. You can assign functions to variables; they can be passed to other functions or returned as results.
Alright now let’s go into the details of the common higher order functions starting from the easiest to the slightly less easy.
Filter is simple to use but also very powerful. We avoided using temporary variables, changing the values inside variables (mutating states) or even using a loop on the array. Aside from the silly variable names like f and A, the code is very expressive in what it does.
Using loops are a very common theme in most imperative programming languages that we take their existence for granted. But when you think functionally, loops are completely unnecessary. In fact they are so unnecessary that some functional languages do not even provide syntax to write loops. We already saw one way we can eliminate loops using filter but more often than not, you would find that map is a more suitable replacement instead of using for and while loops.
A map takes a list and a function and returns a new list. Just like filter, but the new list contains the same number of elements as the input list but they would be transformed by the input function we passed in.
In an imperative style of programming, we would declare loops, variables to iterate over the loops, counters, increments, decrements and more temp variables to do the same operation we just did with three lines of code. With map, we just specify what needs to happen and the rest takes care of itself. But we can get more clever with loops. Sometimes, it is not even necessary to map one list to another to get a result, especially when combining the elements inside the list that is returned after the map. To do that we could use…
Reduce is the operation that is the most confusing initially. But as you use this more and more, it would become natural and obvious. The simplest way to think about it is as a merge operation. The reduce function takes an input list and an input function just like the other two helpers we saw. But it differs in two ways
- The output is not a list but a single value (usually, but you can get creative with it).
- The input function that is passed to the reduce function takes two values instead of one.
- Ok, so there is one more difference — it also takes an initial value.
That doesn’t sound simple at all. But we can break it down. First off the reduce performs squishing or merge of elements of the list.
You may notice that we pass a zero as input to the reduce. This is the initial value that is provided to the input. The reason we need an initial value is that when the reducer executes for the first time, on the first element in the list, it needs something to combine the value with.
So what happens to the value returned by the reducer function?- It is used as the initial value for the next element in the list. We have a special name for the initial value and it is called the Accumulator.
Remember the code to triple all values in the array we used for describing map? How about we sum all the elements of that result. We could do a map followed by a reduce with this sum reducer (this chaining of functions is another cool thing about functional programming) but we could also do both in one shot. Here’s the code
It is important to triple the value b instead of the accumulator. Otherwise we would be tripling the sum after every intermediate result. So map is also just a reduce; however the combining logic of a map is predetermined — list concatenation, whereas we can specify any combining logic we want on the reduce.
Replacing loops in your day-to-day code would be the best place to experiment and learn functional programming. This is not a purist approach but doesn’t require too much learning to get a practical use out of it. Almost every language has some variation of these basic helpers and if not, you could definitely find optimized open source library implementations. Have fun!