Functional programming is an idea, a way of approaching programming, that borrows from mathematics and its idea of what a function is.
In computer science, a function can be defined as a bundle of code that does something—it mutates a data collection, it updates a database, it logs things onto the console, etc. If we want, we can even make it do many of these things at once. A function, in computer science, is a set of procedures that get given a name and can be passed around and invoked when needed.
In mathematics, despite sharing the same name, a function has a stricter definition. A function is a mapping between an input and an output. It does one thing, and one thing only, and no matter what you give it, it always produces the same result. In addition to this mapping, the function will never mutate the input. It produces the output based on what we pass it.
What functional programming is (at a high level), is the use of these ideas in computer programming. It is a way of thinking and approaching a problem. In functional programming, we reduce a problem to small single-purpose functions that we can assemble together like LEGO blocks.
This can be boiled down to three core principles: 1) A function will always only look at the input; 2) A function will always produce an output; 3) All data structures are immutable.
The beauty here is that given, say, a collection of numbers, we can run it through a very complex set of functions and still be sure that our data remains exactly the same in the end.
The function only mutates values inside its scope, but anything coming from the outside remains the same.
In functional programming, there’s an emphasis on clarity, both syntactical and of purpose. Each block has one purpose and nothing else. Below, in Swift, I created a function that multiples all numbers in an Array by 10. This function is created in generic form and added as an extension to Array.
From the outside, the function is named as descriptively as possible so that anyone else interacting with it can see the what without having to deal with the how.
We don’t need to understand the function in order to use it. We call it and, no matter how complex its procedures, it should always produce the same output.
The benefit is that each function can be made and tested in isolation since it does just one thing. And over time, the function can be optimized and made a lot better without it ever impacting the code where it is called.
But, in a world of pure functions, there's still a need to bridge into the real and more messy world of side-effects. These are anything from logging to the console, writing to a file, updating a database, or any external process. The key here is to separate all side-effects from the pure logic of a program and isolate them.
Lastly, with functional programming, there is an incessant creation of copies of the same data, given that functions do not modify their input. This is problem has been solved by persistent data structures.