A wave of functional programming posts, podcasts and tutorials have been emerging since the past years. People are always talking about functional languages like clojure, scala, haskell and others. Many have asked what it brings to the table: lazy evaluation, concurrency, easy to maintain (the code is very brief and concise), reactive programming and more.
As the list goes on, the attention on functional programming increases and the thought of giving it a shot comes to your mind. You start to read some articles and books. The first chapter is great and you are really feeling the hang of it. Some pages after they start talking about lambda calculus, category theory and the stereotype that ‘functional programming is hard and unnatural’ increases in your head.
If you came from an imperative language (OOP), looking at all those declarative code snippets from FP may frighten you. It is true that functional languages really have a lot of complex and beautiful mathematics behind it. Monoids, functors, monads, applicatives, transducers and many others may fear you at first. Do you really need all of that to start?
What do I need to dive into the functional paradigm?
One of the first differences that you can spot is the way of programming, which belongs under the declarative paradigm. Declarative programming focuses on what should be done rather than how (the so famous imperative programming). It is made upon declarative sentences, focusing more on creating expressions and evaluating functions rather than the way that the machine works and how the task will be done. Imperative languages often focus on a procedural approach, explicitly manipulating how the machine works and changing the states of a program, whereas the declarative programming express the logic of the operation (and do not focus on the implementation).
This might be one of the most popular examples when we talk about functional programming. On the first
doubleAll function we tell exactly how the computer should do the operation. We append the double of every number into a new array, but we also could do another operation after that (e.g. increment some counter, print it to the console). We are explicitly telling the machine how to do it. On the second function we do not care about the implementation; instead, we focus on what should be done, passing an anonymous function to
map (which applies the function to the array, creating a new one, fully handling the implementation).
Secondly, I would say one should understand immutability. This is one of the things that makes functional programming a lot different than other paradigms. It basically means that you should stop building structures and changing their properties every time something occurs in your code. Think of your structure as your school notebook; for every annotation the teacher writes to the blackboard, you put it in an empty space, one word next to another, rather than writing them one above other, stacking every word (and ending up with a very crazy and mixed page).
Functions should be treated as data and that means you can return functions or pass them as parameters and even compose then to achieve the desired result. As they are data, they should also be pure; that means if you have a function named
is-number it should, literally, check if it is a number. Don’t try to sneak any other responsibility to it (e.g. print to the console, add some records to a database): it must do what it says. Period. If you want to check if it is a number and then commit it to a database (or any other logging material), create another function to access the database. Then, you can compose both of then to your desired output. Sure that will produce a third, unpure function (database is considered I/O, moreover this new function is not pure), however, now you have two isolated functions, hence improving the maintainability of your code (and debugging!).
With those thoughts in mind you can start to adapt to functional programming. There is a lot more to come, however it can be a bit traumatic to try everything at once.
It is hard to change from a OOP and imperative paradigm, but keep in mind that you should take one step at a time. Instead of going “full functional” with your stack, you can start to tackle some functional concepts in your current language and exercise the ideas in your head.