This is a post to discuss the benefits of functional programming (FP) for those who don’t use functional programming and I guess most relevant for full stack developers – you love your JavaScript and your SQL children equally.
tl;dr: FP combines well with SQL, is easy to learn like Excel, is declarative, makes you think of data as a whole, is backed by mathematics and (IMHO) most importantly has less bugs (which has a compound interest style benefit).
I was reading a functional programming blog post. It’s excellent and teaching me things. As someone already familiar with functional programming I love it. In no way do I want to slander the post. I still feel like a very basic functional programmer and that post explains beautifully, without using libraries, how I can take my functional programming a step further. However I would argue it struggles to convince why someone should start to use functional programming.
Here’s three sections of talking about the hard-to-see benefits of functional programming (emphasis mine):
We could then put those together with pipe() like this:
const comments = pipe(commentStrs, filter(noNazi), take(10), map(emphasize), map(itemize), join('\n'), );If we squint a little, our pipeline isn’t so different from chaining array methods:
const comments = commentStrs .filter(noNazi) .slice(0, 10) .map(emphasize) .map(itemize) .join('\n');Now, someone may feel that the array method chaining looks a little cleaner. They may be right. And someone else may even be wondering why we’d waste time with
pipe()
and those utility functions.
later on:
This [non functional block of code] code is fine. For lots of people, it’s going to be familiar and readable. It accomplishes the same result as the composed version. Why would anyone bother with
pipe()
?
and in the conclusion:
Now, you may not care one whit about functional programming. That’s fine. But using
pipe()
opens up a whole new way to structure programs. With statements, we write code as a series of instructions to the computer. It’s a lot like a recipe in a cookbook. Do this; then do that; then do this other thing. But with composition, we express code as relationships between functions.
I think these arguments for functional programming can be simplified and strengthened.
Declare me a cookbook (its cookbooks all the way down)
Functional programming as I understand it is described as being like a cookbook. It’s declarative – mix this, bake that. You take the output of one part of the recipe and apply it to the next part. You don’t work on protein by protein of the egg, you whisk the whole thing. Maybe you separate the white and the yolk, but you’re always dealing with things as a whole.
Once you start selling functional programming to people as ‘express code as relationships between functions’, I think you have lost. Either they understand what you mean, which means they already are sold, or they don’t understand in which case you will never sell it to them.
Composition encourages us to think about code as relationships between expressions … As a result, our code becomes more declarative.
So ‘relations between expressions’ gives us more declarative code.
I always relate declarative code to SQL. In SQL, the CURSOR
is the only available loop and it is seen as a code smell. WHERE
(filter in FP language), aggregation functions like SUM
(reduce in FP language) and any transformational functions like CONCAT
in SELECT
(map in FP language) are exactly what coders understand and use naturally.
How I think about functional programming is dealing with your whole group of data as one block.
Not row per row, but tables/sets at a time.
Excel
I also come back to Excel. Excel has been used by millions of non-coders to code. It is the most powerful and most used computer platforms.
If non programmers can understand how powerful Excel is then programmers should understand how powerful Excel is without borders.
I also stick to the power of just writing a simple function:
function double (x) { return 2 * x; }
As opposed to wrapping that function up in a class, or just writing 2 * myVar
everywhere. It is a nice balance between DRY and only getting the banana (not the monkey and the rain forest).
1000 years of proofs
The other reference point I keep coming back to, is that functional programming is backed by 1000 years of mathematics. Mapping one set of data onto another is a beautiful mathematical concept. Computer science has 70 years of history, mathematics has thousands of years.
Functional programming came about by mathematicians and computer scientists discovering things at the same time from different angles.
Most people will never have heard of the Church-Turing thesis. In your typical OOP course, frankly in my entire Mathematics and Computer Science degree I don’t remember talking about the Church-Turing thesis, even though we did have a course on Haskell. It was only years later, I think as a part of various links that I came across from Hacker News that I learned more about Haskell, Category Theory and the Church-Turing thesis.
What is the Church-Turing thesis? Here’s a summary (cheers ChatGPT):
It states that any function that can be computed by an algorithm can be computed by a Turing machine. In simpler terms, it suggests that any problem that can be solved by a step-by-step procedure can also be solved by a computer program.
Written in another way – if you can write an algorithm in your programming language, then the computer can solve it. Coding is only so popular because we know it can be calculated. Otherwise it would just be a research topic.
This applies to regular procedural programming as much as it does to functional programming. But if we go Wikipedia we get:
In 1933, Kurt Gödel, with Jacques Herbrand, formalized the definition of the class of general recursive functions: the smallest class of functions (with arbitrarily many arguments) that is closed under composition, recursion, and minimization, and includes zero, successor, and all projections.
This is one of three definitions in the Church-Turing thesis that were proved to be equivalent. The other two definitions were by Alonzo Church (λ-calculus) and Alan Turing (Turning machines). But interestingly this definition is much more relevant to functional programming.
When you are composing functions (passing the result of one function to another), when you are doing function recursion you are standing on the shoulders of Kurt Gödel, whilst Church and Turing look on approvingly. You have a clear, transparent path to proven methods.
I feel their presence in the room when I’m coding. If you’re doing OOP, maybe you think you have the approving gaze of Alan Kay (the originator of OOP concept). But if you’re using Java, C# or C++ (and definitely if you’re using classes in JavaScript), he’s really not a fan:
the C based languages that have been painted with “OOP paint”.
Alan Kay comment (2010)
Start the FP journey
But also, even at the most basic level, replacing loops for map, filter and reduce can be done easily. This is how I taught myself functional programming using general purpose languages. You don’t need to use compose
, pipe
, flow
as mentioned in the blog post. You don’t need monads.
What you need is:
- pass functions as parameters
- return functions
- map
- filter
- reduce
That will get you enough for years of coding. You can learn things like flatMap as a next step.
I’m fine if people write lots and lots of nested functions. It may be ugly but it’s easy for anyone who isn’t familiar with functional programming to read.
compose
, pipe
, flow
similar to arrow functions can all make your code more powerful. If you have a culture that understands functional programming deeply then they are great to use. They’re the next step up. What is great is that there are many more levels up that you can go – category theory is always there waiting for you to learn about. It’s amazingly powerful, but you don’t need it.
Conclusion
So I like functional programming because:
- Its declarative and so my SQL and my regular code become more similar
- Coding declaratively is “good”
- My thinking about my code acts on data as a whole, so my SQL thinking of sets and tables becomes more similar
- Thinking about data as a whole is “good”
- 1) and 3) mean that I can apply the same thinking and coding all the way through my programming stack. A trick I learn in the database can be applied in the front end.
- Its mathematical and so the concepts I use have been proven to work. I can’t be sure we’ll be using
for
andwhile
in a 1000 years, butmap
,filter
andreduce
will still be there
Finally and for me most importantly is that I believe I have less bugs in my code. Removing just the simple off by one error in code has a compound interest style impact on the rest of my code. I have less places to look for bugs in my code, so I spot bugs faster. I spend less time fixing bugs and so less time having to refactor. Bugs get harder and take longer to fix the older they are. I spend more time coming up with new code, thinking about the data and solving the problem better on the first attempt.
I spend my days building and not repairing.