The main goal of this article is to help you improve your English level. I will use Simple English to introduce to you the concepts related to software development. In terms of IT knowledge, it might have been explained better and more clearly on the internet, but remember that the main target of this article is still to LEARN ENGLISH.
Hi, I'm Tuan, a Full-stack Web Developer from Tokyo 😊. Follow my blog to not miss out on useful and interesting articles in the future.
The first step to understanding Functional Programming is the hardest, but it doesn't have to be if you have the right attitude.
Learning to Drive
When we first started learning to drive, it seemed easy when we watched other people do it, but it was harder than we expected. We practiced in our parents' car and only drove on the highway once we had mastered the streets in our neighborhood.
After a lot of practice and some scary moments, we got our license and drove our car whenever we could. We got better and better and our confidence grew. Eventually, we had to drive someone else's car or buy a new one. The first time was strange because we had only been a passenger before, but the second time was easier because the car was similar to the old one.
Learning programming languages is similar - the first is the hardest, but subsequent ones are easier. You ask questions like how to create a module or search an array, and you know you can learn the language because it's similar to the one you already know, with a few new features.
Your First Spaceship
No matter how much experience you have driving cars, flying a spaceship would be a completely new experience. You would need to start from the beginning and learn how to fly the spaceship, as the skills you have from driving on the ground would not be useful.
Similarly, when learning Functional Programming, you should expect that things will be very different and that much of what you know about programming will not be applicable. Functional Programming will teach you to think differently and you may never go back to the old way of thinking.
Forget Everything You Know
People often say that learning Functional Programming is like starting from scratch, but it's not completely true. There are some similarities, but it's best to expect that you will need to relearn a lot of things. If you have the right attitude and expectations, you won't give up when things get difficult.
There are a lot of things that you are used to doing as a programmer that you can't do with Functional Programming, like not having a reverse gear in a car. It's important to understand that you don't need reverse in a spaceship because of its ability to move in three dimensions.
Learning Functional Programming takes time, so be patient and take your time to understand the concepts and coding examples. Don't rush, and make sure you understand everything before you move on.
Purity
When Functional Programmers talk about purity, they mean that a function only uses its input parameters and does not have any other effects. An example of a Pure Function in Javascript is a function that only uses its input parameters and does not have any other effects.
Here’s an example in Javascript of a Pure Function:
var z = 10;
function add(x, y) { return x + y;
}
The add function only uses the inputs x and y and does not interact with any other variables. It simply adds the two inputs together and returns the result. If the add function did interact with other variables, it would no longer be considered a pure function.
Here’s another function to consider:
function justTen() { return 10;
}
A pure function called justTen can only return a constant value because it has no inputs. This is not very useful, so it would be better to define justTen as a constant instead. To be useful, a pure function must take at least one parameter.
Consider this function:
function addNoReturn(x, y) { var z = x + y
}
This function takes two numbers, adds them together, and stores the result in a variable, but it does not give the result back. This means it is a pure function, since it only works with the inputs it is given. However, since it does not return anything, it is not useful. All pure functions must return something in order to be useful.
Let’s consider the first add function again:
function add(x, y) { return x + y;
}
console.log(add(1, 2)); // prints 3
console.log(add(1, 2)); // still prints 3
console.log(add(1, 2)); // WILL ALWAYS print 3
The add function will always produce the same result when given the same inputs. However, if the add function uses an outside value, then the result may be unpredictable.
writeFile(fileName);
updateDatabaseTable(sqlCmd);
sendAjaxRequest(ajaxRequest);
openSocket(ipAddress);
Functions in imperative programming languages like Javascript, Java, and C# often have side effects, which means they do more than just take in inputs and return outputs. This makes debugging difficult because a variable can be changed anywhere in the program, making it hard to find the source of the bug. Pure functions, on the other hand, have no side effects.
You are probably wondering now, “HOW THE HELL DO I DO ANYTHING WITH ONLY PURE FUNCTIONS?!”
In Functional Programming, you cannot completely avoid writing code that has side effects, as programs need to interact with the real world. However, you should try to minimize the amount of code with side effects and keep it separate from the rest of the program.
Immutability
Do you remember when you first saw the following bit of code:
var x = 1;
x = x + 1;
In Functional Programming, you cannot change the value of a variable once it has been set. This is different from Imperative Programming, where you can take the current value of a variable, add 1 to it, and put the result back into the variable. In Elm, a Pure Functional Programming Language for Web Development, variables are constants and cannot be changed.
addOneToSum y z = let x = 1 in x + y + z
If you don't know what ML-Style syntax is, I can explain. The function addOneToSum takes two numbers, y and z. Inside the function, the number 1 is assigned to the variable x. The result of the calculation 1 + y + z is then returned.
Once again, I can hear you ask “HOW THE HELL AM I SUPPOSED TO DO ANYTHING WITHOUT VARIABLES?!”
When we want to change variables, there are two main types of changes: changing one value of an object or record (multi-valued changes) and changing a loop counter (single-valued changes). Functional programming solves these changes by making a copy of the record or loop counter with the changed values, without having to copy all parts of the record. It does this efficiently by using data structures that make this possible, and without using loops.
“WHAT NO VARIABLES AND NOW NO LOOPS?! I HATE YOU!!!”
Wait a minute, we can still do looping in Functional Programming, it's just that there are no specific loop commands like for, while, do, repeat, etc. Instead, we use recursion to do looping. Here are two ways to do looping in Javascript.
// simple loop construct
var acc = 0;
for (var i = 1; i <= 10; ++i) acc += i;
console.log(acc); // prints 55
// without loop construct or variables (recursion)
function sumRange(start, end, acc) { if (start > end) return acc; return sumRange(start + 1, end, acc + start)
}
console.log(sumRange(1, 10, 0)); // prints 55
Recursion is a way of achieving the same result as a for loop, but instead of modifying the old values, it uses new values calculated from the old. This can be hard to understand in Javascript because the syntax is complicated and people are not used to thinking recursively. In Elm, it is easier to read and understand.
sumRange start end acc = if start > end then acc else sumRange (start + 1) end (acc + start)
Here’s how it runs:
sumRange 1 10 0 = -- sumRange (1 + 1) 10 (0 + 1)
sumRange 2 10 1 = -- sumRange (2 + 1) 10 (1 + 2)
sumRange 3 10 3 = -- sumRange (3 + 1) 10 (3 + 3)
sumRange 4 10 6 = -- sumRange (4 + 1) 10 (6 + 4)
sumRange 5 10 10 = -- sumRange (5 + 1) 10 (10 + 5)
sumRange 6 10 15 = -- sumRange (6 + 1) 10 (15 + 6)
sumRange 7 10 21 = -- sumRange (7 + 1) 10 (21 + 7)
sumRange 8 10 28 = -- sumRange (8 + 1) 10 (28 + 8)
sumRange 9 10 36 = -- sumRange (9 + 1) 10 (36 + 9)
sumRange 10 10 45 = -- sumRange (10 + 1) 10 (45 + 10)
sumRange 11 10 55 = -- 11 > 10 => 55
55
It may seem like for loops are easier to understand, but non-recursive loops require Mutability, which is not ideal. Immutability has many benefits, such as preventing accidental mutations and making multi-threaded programs safer. If I had known about immutability when I was writing a game engine in before, I would have had fewer bugs. Immutability makes code simpler and safer.
My Brain!!!!
That is all I will discuss in this article, but I will talk about Higher-order Functions, Functional Composition, Currying and other topics in future articles.
And Finally
As always, I hope you enjoyed this article and learned something new. Thank you and see you in the next articles!
If you liked this article, please give me a like and subscribe to support me. Thank you. 😊
The main goal of this article is to help you improve your English level. I will use Simple English to introduce to you the concepts related to software development. In terms of IT knowledge, it might have been explained better and more clearly on the internet, but remember that the main target of this article is still to LEARN ENGLISH.