🤔So You Want to be a Functional Programmer (Part 3)🤓
The first step to understanding Functional Programming is the hardest, but it doesn't have to be if you have the right attitude.
Previous parts: Part 1, Part 2
Function Composition
As programmers, we want to find ways to do our work once and be able to use it again. However, it can be difficult to make code that is specific enough to be useful but also general enough to be reused.
Functional Programming provides a way to achieve this balance by creating small, specific functions that can be combined like Lego™ blocks to create more complex functionality.
This is called Function Composition.
So how does it work? Let’s start with two Javascript functions:
var add10 = function (value) {
return value + 10;
};
var mult5 = function (value) {
return value * 5;
};
This is too verbose so let’s rewrite it using fat arrow notation:
var add10 = value => value + 10;
var mult5 = value => value * 5;
We want to create a function that takes a value, adds 10 to it, and then multiplies the result by 5.
var mult5AfterAdd10 = value => 5 * (value + 10)
Even though this is a very basic example, we don't want to have to write the function from the beginning. We could make a mistake like forgetting the parentheses and we already have functions that add 10 and multiply by 5. So instead, let's use the add10 and mult5 functions to create our new function.
var mult5AfterAdd10 = value => mult5(add10(value));
We used existing functions to create a new function called mult5AfterAdd10, but there is a better way to do this. In mathematics, "f composed with g" (or "f after g") is a concept called functional composition.
This means that (f ∘ g)(x) is the same as calling f after calling g with x, or simply, f(g(x)).
In our example, we have mult5 ∘ add10, which is the same as "mult5 after add10". This is why we named our function mult5AfterAdd10.
We called mult5 after we called add10 with a value, which is the same as mult5(add10(value)).
We can pass the value of x through a series of functions t, r, s, and so on, and the result of each function will be passed to the next one. This would look like g(h(s(r(t(x))))).
Trouble in Paradise
We have seen how to use function composition and how to write our functions in a concise way for clarity and flexibility. Now let's try using these ideas in a different situation and see how it works.
For example, if we replace add10 with add, what would happen?
const add = (x, y) => x + y;
const mult5 = (value) => value * 5;
We can write a function that takes a number as an argument and returns the number multiplied by 5 if it is greater than 10.
var mult5AfterAdd10 = mult5(add(10)); // this doesn't work
This would not work because the add function requires two inputs to be given in order to work. This would look like: add(parameter1, parameter2);
The code is incorrect because the add function is only receiving one of its two parameters, which is causing incorrect results to be passed to the mult5 function. This will lead to incorrect results.
Function composition is not useful in this situation because the two functions cannot be combined.
It would be helpful if there was a way to give the add function one of its parameters ahead of time, and then the second parameter could be given when the mult5AfterAdd10 function is called.
This is possible with a technique called Currying.
My Brain!!!!
Enough for now.
In subsequent parts of this article, I’ll talk about Currying, common functional functions (e.g map, filter, fold etc.), Referential Transparency, and more.
Up next: Part 4
Mình hy vọng bạn thích bài viết này và học thêm được điều gì đó mới.
Donate mình một ly cafe hoặc 1 cây bút bi để mình có thêm động lực cho ra nhiều bài viết hay và chất lượng hơn trong tương lai nhé. À mà nếu bạn có bất kỳ câu hỏi nào thì đừng ngại comment hoặc liên hệ mình qua: Zalo - 0374226770 hoặc Facebook. Mình xin cảm ơn.
Momo: NGUYỄN ANH TUẤN - 0374226770
TPBank: NGUYỄN ANH TUẤN - 0374226770 (hoặc 01681423001)
All rights reserved