4.0 - Practice

In the previous chapters we covered the very basics of functional programming and how it differs from the other mainstream style - imperative programming. We explained the concept of functions, what it means when we say that a function is pure and why is it important. All those pure functions were much easier to write, use and test! But that’s not all there is to it. It’s a good start, but we’ve just scratched the surface....

4.1 - Recursion

Loops are the basic control flow structure we use in imperative programming whenever we want our program to do something multiple times. E.g. if we wanted to find the largest element in array, we’d need to check all the array elements, so we can put the checking code in a loop and execute it as many times as there are elements: function maxLoop = function(array){ if(array.length == 0){ return null; } let max = Number....

4.2 - Immutable data structures

The definition of immutable data is completely contained in the name - it’s data that we cannot change or mutate. Since this concept is defined by what it isn’t rather than what it is, we’ll start with an explanation of its opposite - mutable data What is mutable data? Simply put, mutable data structures are the ones that we can change over the course of time. In JavaScript, regular objects are the typical example of this behavior....

4.3 - Higher order functions

There’s a lot of hype around higher order functions and closely related concepts like functions as objects and closures. In fact, presence or absence of this particular feature has been used as a rule of thumb check to determine whether a language can be called functional. In this chapter we’ll define these concepts, clarify any differences between them and then show how and why does this actually help us write awesome software easily....

4.4 - Lazy Evaluation

In previous chapters we already noticed that in functional programming we don’t really care much about the exact order in which the individual steps of our programs are executed. Instead, we just specify what kind of result we want and based on which parameters and let the environment take care of the rest. That is the reward we get for using pure functions. However, our own comfort is not the only benefit we get....

4.5 - Memoization

In this chapter, we’ll revisit some ideas we introduced previously - function purity and inherent side effects. Let’s start by remembering that pure functions can, in principle, be replaced with a lookup table. Obviously, that is not a very practical approach with functions where there is too many input parameter combinations, e.g. a lookup table for sum of two numbers would need to be infinitely large: a b sum … … … 0 0 0 0 1 1 1 0 1 1 1 2 1 2 3 2 1 3 2 2 4 2 3 5 … … … On the other hand, when the number of different input combinations is fairly small, this is a perfectly reasonable option....

4.6 - Arity, partial application and currying

In this chapter we are going to play with another important property of functions - arity. In simple terms, arity represents the number of input parameters a function expects. So, a function that does not take any parameters has an arity of zero, a function that takes one parameter has an arity of one, and so on. In some programming languages, a function can have optional parameters, sometimes with a default value in case it was omitted in the function call....

4.7 - Sequence transformations: map, reduce and others

We’ve already shown that in functional programming we prefer to use recursive functions over imperative loops with mutable state, and we’ve demonstrated the power of recursion in a few examples. However, as simple as the examples are, it would simply be too tedious to write a fully-blown recursive function every single time we want to have some repetition in our code. A very common reason to repeatedly evaluate the same code against different values happens whenever we need to process sequential data such as collections, lists, arrays, lines of text....

5.0 - What about side effects?

Throughout this book we’ve focused on pure functions and questions like: why are they so good how to write them how to use, reuse and compose them But, as we are unfortunately aware, we do need side effects. In fact, side effects are typically the very purpose of the system in question. Imagine if you walked to your ATM, swiped the card and selected the amount to withdraw only to be brushed off by the machine that says:...

5.1 - Separation of Concerns

The first technique we’ll use is a special case of separation of concerns. Specifically, here we’ll strive to separate the pure code that contains the core logic of the system we are building from the impure (but necessary!) code that handles all the bits and pieces we need to actually use it, usually involving user interaction, database persistence and similar. Let’s illustrate this with an example. We’ll write a program that lets the user input a number, calculates the factorial of that number and then shows a message with the result....