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 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 never mutate sthe input. It produces the output based on what we pass it.
What functional programming is—at a high level—is the use of the mathematical definition of a function in computer programming. 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. 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 code that produces 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.