Introduction
Is Functional Programming any style of code that utilizes functions? If only it was that simple!
Functions are indeed at the core of Functional Programming, but it's how we use those functions that make our implementation functional.
This article aims to lay down some fundamentals of Functional Programming, while mainly pertaining to their application in JavaScript
, that will help you understand :
- What are Functions?
- Functions versus Procedures
- Declarative versus Imperative Programming
- Understanding Function Inputs and Outputs
These foundations will immensely aid you in grasping further concepts of Functional JavaScript, to be covered in future articles, if this one helps.
The next article will cover :
- Function Purity (Pure versus Impure Functions)
- Side Effects
- Extracting and Containing Impurity
- How all of this collectively defines what Functional Programming is, and why it is used
- Is
JavaScript
a Functional Programming Language? - Why consider Functional Programming style for your code?
Stay tuned!
1. What are Functions?
Well, like any introductory programming class will tell you, a function is a reusable piece of code that performs some task upon execution. While this definition is reasonable, it misses out an important perspective that is the core of a function as it applies to Functional Programming.
Let's try to understand Functions more completely, with the example of very basic Mathematics.
You may remember reading about f(x)
in school, or the equation y = f(x)
.
Let's assume the equation f(x) = x2 - 1
. What does that mean? What does it mean to graph that equation? Here's the graph:
It's equivalent to :
function f(x) {
return Math.pow(x,2) - 1;
}
What you can notice is that for any value of x
, say 1
, if you plug it into the equation, you get 0
. What is 0
, though? It's the return value of the f(x)
function, which we earlier said represents a y
value.
In math, a function always takes input(s), and always gives an output. A term you'll often hear around FP is "morphism"; this is a fancy way of describing a set of values that maps to another set of values, like the inputs of a function related to the outputs of that function.
In our code, however, we can define functions with all sorts of input(s) and output(s), even though they'll rarely be interpreted as a visually plotted curve on a graph.
As such, a more complete definition of function would be :
A function is the semantic relationship between input and computed output.
Also note the usage of
function
and function throughout this article. While function is the concept we're discussing,function
is just theJavaScript keyword
.
Essentially, Functional Programming is about embracing using functions
as functions in this mathematical sense.
2. Functions vs Procedures?
The terms Functions and Procedures are often used interchangeably, but they actually mean different things.
A Procedure is an arbitrary collection of functionality. It may have inputs, it may not. It may have an output (as a return
value), it may not.
Whereas, a Function takes input(s) and definitely always has a return
value.
For Functional Programming, we use functions as much as possible, and trying to avoid procedures wherever possible. All your functions should take input(s) and return output(s).
Based upon this knowledge, let's consider the following example :
// Example 1: Function or Procedure?
function addPokémon(team1 = 0, team2 = 0, team3 = 0) {
var total = team1 + team2 + team3;
console.log(total);
}
function countPokémon(currentTeam = 6, ...args) {
return addPokémon(currentTeam, ...args);
}
countPokémon();
// Output : 6
countPokémon(6, 5, 6);
// Output : 17
Try to assess whether function
addPokémon
and countPokémon
are functions or procedures?
Here are some basic observations :
-
addPokémon
has a defined input, but no output specified byreturn
. It should be a procedure. -
countPokémon
has a defined input and a definedreturn
, so it should be a function?
We're correct about addPokémon
being a procedure, but countPokémon
is also a procedure, and not a function, since it makes a call to a procedure within itself.
In summary :
Note that a
function
that calls a procedure within itself, is also a procedure. The "impurity" of a procedure, which is a concept to be explained further down, trickles down and "pollutes" all those who directly or indirectly call it.
Now, we would probably like to understand how to convert the last example's procedures into functions?
Based on the more complete definition of a function mentioned in the last section, try to make changes to the last example, before looking ahead for one of many possible solutions. For this example, it should be pretty straight-forward.
// Example 2: Converting Procedures to Functions?
function addPokémon(team1 = 0, team2 = 0, team3 = 0) {
var total = team1 + team2 + team3;
return total;
// Instead of logging a value, we returned it,
// so there's a proper output/return now.
}
function countPokémon(currentTeam = 6, ...args) {
return addPokémon(currentTeam, ...args);
// Now, a call to a function, not a procedure, is returned
}
console.log(countPokémon());
// Output : 6
console.log(countPokémon(6, 5, 6));
// Output : 17
Let's look at one more example for differentiating procedures and functions.
// Example 3. Identifying functions and procedures
function neighbouringPokémonID(x) {
x = Number(x);
return [x - 1, x + 1];
}
function generateNeighboursForTeam(team) {
var teamIDs = Object.keys(team);
teamIDs.forEach(element =>
console.log(neighbouringPokémonID(element)));
}
var myTeam = {
25: "Pikachu",
155: "Cyndaquil"
};
generateNeighboursForTeam(myTeam);
// Output :
// [24, 26]
// [154, 156]
This snippet effectively returns the Pokédex IDs of the immediate neighbours of a Pokémon, given its own ID.
Clearly, neighbouringPokémonID
is a function, as it has an input and return
s an output based upon it.
Also, generateNeighboursForTeam
is a procedure, as it doesn't return
anything.
Once again, we can modify this example such that both are functions.
// Example 4. Converting the procedure to a function
function neighbouringPokémonID(x) {
x = Number(x);
return [x - 1, x + 1];
}
function generateNeighboursForTeam(team) {
var teamIDs = Object.keys(team);
var neighbourIDs = [];
// Use a temporary array to store computation
teamIDs.forEach(element =>
neighbourIDs.push(neighbouringPokémonID(element)));
return neighbourIDs;
}
var myTeam = {
25: "Pikachu",
155: "Cyndaquil"
};
generateNeighboursForTeam(myTeam);
// Output :
// [[24, 26],[154, 156]]
3. Declarative vs Imperative Programming?
Another basic concept to be familiar with is, the distinction between Declarative and Imperative styles of coding, which is honestly a bit relative in its meaning.
There's no style that's absolutely Declarative or absolutely Imperative. It's a spectrum in itself.
That said, let's introduce ourselves to a common, simple definition.
“Imperative programming is like how you do something, and Declarative programming is more like what you do.”
It's a bit ambiguous and open-ended, so let's take a small example.
Suppose, you are trying to help your little brother with the basics of the latest Pokémon game. Specifically, about catching wild Pokémon.
Declarative: Throw a pokéball when the pokémon is weak. (What to do)
Imperative: When the health bar of the pokémon is below 30%, press X to throw a pokéball. (Exactly how to do it)
In general, explicitly listing out all the steps one by one, is Imperative. It's rather robotic to understand, and requires going through it line by line.
And utilizing some level of abstraction and trusted helper functions, to list the steps in a manner in which it only presents the basic idea, is Declarative. It's easier to understand, as we don't need to bother about how something is happening, rather what is happening.
As what and how can be rather subjective, we can't draw a hard boundary around what is declarative or imperative.
For example, for a person programming in machine language, which is super imperative, Java can seem rather declarative. Or for a person who works on a purely functional language, like Haskell or Clojure, even functional implementations in JavaScript can feel rather imperative.
Our concern at the moment, which is to set the foundations of Functional Programming and Functional JavaScript, we need to understand that we should make our code as declarative as possible, by utilizing functions.
Moving on, let's understand a bit more about Function Inputs and Outputs.
4. Function Inputs
This section covers some more aspects of Function Inputs, chiefly :
- Arguments and Parameters
- Defaulting Parameters
- Counting Inputs
- Arrays of Arguments
- Parameter Destructuring
- Benefits of Declarative Style
- Named Arguments
- Unordered Parameters
Let's get started.
a. Arguments and Parameters
There's often a slight confusion about the difference between arguments and parameters.
Put simply, arguments are the values you pass into a function
, and parameters are the named variables inside the function
that receive those values.
Note: In JavaScript, the number of arguments do not need to match the number of parameters. If you pass more arguments than you have declared parameters to receive them, the values pass in just fine.
These extra arguments can be accessed in a few ways, including the
args
object. If you pass fewer arguments, each unmatched parameter is assignedundefined
.
b. Defaulting Parameters
Parameters can declare default values. In the case where the argument for that parameter is not passed, or it's passed the value undefined
, the default assignment expression is substituted.
function f(x = 10) {
console.log(x);
}
f(); // Output : 10
f(undefined); // Output : 10
f(null); // Output : null
f(0); // Output : 0
It's always a good practice to think about any default cases that can aid the usability of your functions.
c. Arity, or Count of Inputs
The number of arguments a function
"expects" is determined by the number of parameters that are declared.
function f(x,y,z,w) {
// something
}
f.length;
// Output :
// 4
f(..)
expects 4
arguments, as it has 4
declared parameters. This count has a special term: Arity, which is the number of parameters in a function
declaration. The arity of f(..)
is 4
.
Furthermore, a function
with arity 1 is additionally called unary, a function
with arity 2 is also called binary, and a function
with arity 3 or higher is named n-ary.
The length
property of that function
reference returns its arity.
While this may sound simple, the implications are far-reaching.
One reason for determining the arity during execution would be if a piece of code received a function reference from multiple sources, and has to send different values depending on the arity of each.
For example, let's say a fn
function reference could expect one, two, or three arguments, but you always want to just pass a variable x
in the last position:
// `fn` is set to some function reference
// `x` exists with some value
if (fn.length == 1) {
fn(x);
}
else if (fn.length == 2) {
fn(undefined, x);
}
else if (fn.length == 3) {
fn(undefined, undefined, x);
}
Tip: The
length
property of a function is read-only and it's determined at the time you declare the function. It should be thought of as essentially a piece of metadata that describes something about the intended usage of the function.One gotcha to be aware of is that certain kinds of parameter list variations can make the
length
property of the function report something different than you might expect:
function foo(x,y = 2) {
// something
}
function bar(x,...args) {
// something
}
function baz( {a,b} ) {
// something
}
foo.length; // Output : 1
bar.length; // Output : 1
baz.length; // Output : 1
What about counting the number of arguments the current function call received? This was once trivial, but now the situation is slightly more complicated. Each function has an arguments
object (array-like) available that holds a reference to each of the arguments passed in. You can then inspect the length
property of arguments
to figure out how many were actually passed:
function f(x,y,z) {
console.log(arguments.length);
}
f(3, 4);
// Output :
// 2
As of ES5 (and strict mode, specifically), arguments
is considered by some to be sort of deprecated; many avoid using it if possible. However, arguments.length
, and only that, is okay to keep using for those cases where you need to care about the passed number of arguments.
A function signature that accepts an indeterminate amount of arguments is referred to as a variadic function.
Say you do need to access the arguments in a positional array-like way, possibly because you're accessing an argument that doesn't have a formal parameter at that position. How do we do it?
ES6 to the rescue! Let's declare our function with the ...
operator, referred to as "spread", "rest", or "gather":
function f(x,y,z,...args) {
// something
}
The ...args
in the parameter list is an ES6 declarative form that tells the engine to collect all remaining arguments (if any) not assigned to named parameters, and put them in a real array named args
. args
will always be an array, even if it's empty. But it will not include values that are assigned to the x
, y
, and z
parameters, only anything else that's passed in beyond those first three values.
function f(x,y,z,...args) {
console.log(x, y, z, args);
}
f(); // undefined undefined undefined []
f(1, 2, 3); // 1 2 3 []
f(1, 2, 3, 4); // 1 2 3 [ 4 ]
f(1, 2, 3, 4, 5); // 1 2 3 [ 4, 5 ]
So, if you want to design a function that can account for an arbitrary number of arguments, use ...args
.
You can use the ...
operator in the parameter list even if there are no other formal parameters declared.
function (...args) {
// something
}
args
will now be the complete array of arguments, whatever they are, and you can use args.length
to know exactly how many arguments have been passed in.
d. Arrays of Arguments
What if you wanted to pass along an array of values as the arguments to a function call?
function f(...args) {
console.log(args[3]);
}
var arr = [1, 2, 3, 4, 5];
f(...arr);
// Output :
// 4
Our new friend, the ...
operator is used here, but now not just in the parameter list; it's also used in the argument list at the call-site.
It has the opposite behavior in this context.
In a parameter list, we said it gathered arguments together. In an argument list, it spreads them out. So the contents of arr
are actually spread out as individual arguments to the f(..)
call.
Also, multiple values and ...
spreadings can be interweaved, as needed:
var arr = [2];
f(1, ...arr, 3, ...[4,5]);
// Output :
// 4
Think of
...
in this symmetric sense: in a value-list position, it spreads. In an assignment position -- like a parameter list, because arguments get assigned to parameters -- it gathers.
...
makes working with arrays of arguments much easier.
e. Parameter Destructuring
Consider the variadic f(..)
from the previous section:
function f(...args) {
// something
}
f( ...[1,2,3]);
What if we wanted to change that interaction so the caller of our function passes in an array of values instead of individual argument values? Just drop the two ...
usages:
function f(args) {
// something
}
f([1,2,3]);
Simple enough. But what if now we wanted to give a parameter name to each of the first two values in the passed-in array? We aren't declaring individual parameters anymore, so it seems we lost that ability.
Thankfully, ES6 destructuring is the answer. Destructuring is a way to declare a pattern for the kind of structure (object, array, etc.) that you expect to see, and how decomposition (assignment) of its individual parts should be processed.
Consider:
function f([x,y,...args] = []) {
// something
}
f([1,2,3]);
Do you spot the [ .. ]
brackets around the parameter list now? This is called array parameter destructuring.
In this example, destructuring tells the engine that an array is expected in this assignment position (aka parameter). The pattern says to take the first value of that array and assign it to a local parameter variable called x
, the second to y
, and whatever is left is gathered into args
.
f. Benefits of Declarative Style
Considering the destructured f(..)
we just looked at, we could instead have processed the parameters manually:
function f(params) {
var x = params[0];
var y = params[1];
var args = params.slice(2);
// something
}
But here we highlight a principle that declarative code communicates more effectively than imperative code.
Declarative code (for example, the destructuring in the former f(..)
snippet, or the ...
operator usages) focuses on what the outcome of a piece of code should be.
Imperative code (such as the manual assignments in the latter snippet) focuses more on how to get the outcome. The outcome is coded there, but it's not as clear because it's crowded by the details of how we got there.
The earlier f(..)
is regarded as more readable, because the destructuring hides the unnecessary details of how to manage the parameter inputs.
Wherever possible, we should strive for declarative, self-explanatory code.
g. Named Arguments
Just as we can destructure array parameters, we can destructure object parameters:
function f({x,y} = {}) {
console.log(x, y);
}
f({
y: 3
});
// Output :
// undefined 3
We pass in an object as the single argument, and it's destructured into two separate parameter variables x
and y
, which are assigned the values of those corresponding property names from the object passed in. It didn't matter that the x
property wasn't on the object; it just ended up as a variable with undefined
like you'd expect.
With a normal call-site like f(undefined,3)
, position is used to map from argument to parameter; we put the 3
in the second position to get it assigned to a y
parameter.
But at this call-site where parameter destructuring is involved, a simple object-property indicates which parameter (y
) the argument value 3
should be assigned to.
Some languages have an explicit feature for this: named arguments. In other words, at the call-site, labeling an input value to indicate which parameter it maps to. JavaScript doesn't have named arguments, but parameter object destructuring is the next best thing.
h. Unordered Parameters
Another key benefit is that named arguments, by virtue of being specified as object properties, are not fundamentally ordered. That means we can specify inputs in whatever order we want:
function f({x,y} = {}) {
console.log(x, y);
}
f({
y: 3
});
// Output :
// undefined 3
The call-site is no longer cluttered by ordered-placeholders like undefined
to skip a parameter.
Function Outputs
This section covers some more aspects of Function Outputs.
In JavaScript, functions
always return
a value. These three functions all have identical return
behavior:
function foo() {}
function bar() {
return;
}
function baz() {
return undefined;
}
The undefined
value is implicitly returned
if you have no return
or if you just have an empty return;
.
But keeping as much with the spirit of Functional Programming function definition as possible -- using functions and not procedures -- our functions should always have outputs, which means they should explicitly return
a value, and usually not undefined
.
A return
statement can only return a single value. So if your function needs to return multiple values, your only viable option is to collect them into a compound value like an array or an object:
function f() {
var retValue1 = 1;
var retValue2 = 3;
return [retValue1, retValue2];
}
Then, we'll assign x
and y
from two respective items in the array that comes back from f()
:
var [x, y] = f();
console.log(x + y);
// Output : 4
Collecting multiple values into an array (or object) to return, and subsequently destructuring those values back into distinct assignments, is a way to transparently express multiple outputs for a function.
Let's cover some concepts related to Function Outputs, chiefly :
- Early Returns
- Un
return
ed Outputs - Higher-Order Functions (HOFs or Functions of Functions)
a. Early Returns
The return
statement doesn't just return a value from a function
. It's also a flow control structure; it ends the execution of the function
at that point.
A function
with multiple return
statements thus has multiple possible exit points, meaning that it may be harder to read a function to understand its output behavior if there are many paths that could produce that output.
Consider:
function f(x) {
if (x > 10) return x + 1;
var y = x / 2;
if (y > 3) {
if (x % 2 == 0) return x;
}
if (y > 1) return y;
return x;
}
f(2); // Output : 2
f(4); // Output : 2
f(8); // Output : 8
f(12); // Output : 13
First off, f(x)
is highly unreadable and difficult to follow. Dry-running this in your mind is quite tedious. That's because we're using return
not just to return different values, but also as a flow control construct to quit a function's execution early in certain cases.
Consider this version of the code:
function f(x) {
var retValue;
if (retValue == undefined && x > 10) {
retValue = x + 1;
}
var y = x / 2;
if (y > 3) {
if (retValue == undefined && x % 2 == 0) {
retValue = x;
}
}
if (retValue == undefined && y > 1) {
retValue = y;
}
if (retValue == undefined) {
retValue = x;
}
return retValue;
}
This version is unquestionably more verbose. But it is slightly simpler logic to follow, because every branch where retValue
can get set is guarded by the condition that checks if it's already been set.
Rather than return
ing from the function early, we used normal flow control (if
logic) to determine the retValue
's assignment. At the end, we simply return retValue
.
In summary, it's more readable to have just a single return
at the end. Try to figure out the most explicit way to express the logic.
b. Unreturn
ed Outputs
One technique that you've probably used in most code you've written, and maybe didn't even think about it much, is to have a function output some or all of its values by simply changing variables outside itself.
Remember our f(x) = x2 - 1
function from earlier? We could have defined it like this in JS:
var y;
function f(x) {
y = (2 * Math.pow( x, 2 )) + 3;
}
We could just as easily have return
d the value instead of setting it into y
from within the function:
function f(x) {
return (2 * Math.pow( x, 2 )) + 3;
}
Both functions accomplish the same task, so is there any reason we should pick one version over the other?
One way to explain the difference is that the return
in the latter version signals an explicit output, whereas the y
assignment in the former is an implicit output.
But changing a variable in an outer scope, as we did with the y
assignment inside of f(..)
, is just one way of achieving an implicit output. A more subtle example is making changes to non-local values via reference.
Consider:
function sum(list) {
var total = 0;
for (let i = 0; i < list.length; i++) {
if (!list[i]) list[i] = 0;
total = total + list[i];
}
return total;
}
var nums = [ 1, 3, 9, 27, , 84 ];
sum(nums);
// Output :
// 124
The most obvious output from this function is the sum 124
, which we explicitly return
ed. But instead of an undefined
empty slot value in position 4
, now there's a 0
.
The harmless looking list[i] = 0
operation ended up affecting the array value on the outside, even though we operated on a local list
parameter variable.
Why? Because list
holds a reference-copy of the nums
reference, not a value-copy of the [1,3,9,..]
array value. JavaScript uses references and reference-copies for arrays, objects, and functions, so we may create an accidental output from our function all too easily.
This implicit function output has a special name in the FP world: Side Effects. And a function that has no side effects also has a special name: Pure Function. Both these concepts will be covered in the next article.
c. Higher-Order Functions (HOFs or Functions of Functions)
Functions can receive and return values of any type. A function that receives or returns one or more other function values has the special name: higher-order function.
Consider:
function forEach(list,fn) {
for (let v of list) {
fn( v );
}
}
forEach( [1,2,3,4,5], function each(val){
console.log( val );
} );
// Output :
// 1 2 3 4 5
forEach(..)
is a higher-order function because it receives a function as an argument.
A higher-order function can also output another function, like:
function f() {
return function upper(x){
return x.toUpperCase();
};
}
var g = f();
g("Hello!");
// Output :
// HELLO!
return
is not the only way to "output" an inner function:
function f() {
return g(function upper(x){
return x.toUpperCase();
} );
}
function g(func) {
return func("Hello!");
}
f();
// Output :
// HELLO!
Functions that treat other functions as values are higher-order functions by definition. These are very crucial to Functional Programming!
Summary
We covered the following concepts in this article :
- What are Functions?
- Functions versus Procedures
- Declarative versus Imperative Programming
- Function Inputs
- Arguments and Parameters
- Defaulting Parameters
- Counting Inputs
- Arrays of Arguments
- Parameter Destructuring
- Benefits of Declarative Style
- Named Arguments
- Unordered Parameters
- Function Outputs
- Early Returns
- Un
return
ed Outputs - Higher-Order Functions (HOFs or Functions of Functions)
The next article will cover :
- Function Purity (Pure versus Impure Functions)
- Side Effects
- Extracting and Containing Impurity
- How all of this collectively defines what Functional Programming is, and why it is used
- Is
JavaScript
a Functional Programming Language? - Why consider Functional Programming style for your code?
Credits
- Functional-Light JS book by Kyle Simpson, for inspiring this article, as well as,
- FrontEnd Masters : Functional-Light JavaScript
Thanks a lot for reading! ❤️
Dev.to | Twitter | Hashnode | Medium | GitHub | LinkedIn | Buy Me A Coffee
Top comments (33)
I find FP to be intriguing, but I have been making apps with Svelte lately. I find it difficult to use FP patterns with a framework that is based on a MVVM pattern. How can I make use of FP with MVVM?
I am looking forward to the rest of the articles in this series. Thank you for doing this!
Agreed. FP patterns, in general, can sometimes be difficult to implement with many frameworks. In that case, we can only try our best to accommodate them. Perhaps, I'll try to cover this by taking examples of some common frameworks. I personally haven't worked with Svelte yet, I'll check it out sometime.
In my own view, a framework that doesn't allow enough freedom to try various design patterns, is too restrictive to work with; since it basically feeds you its own guidelines at that point, and forces you to only think along those lines.
This might be a good idea to cover later. Thanks for the suggestion!
And, thank you for enjoying this! It takes a lot of time to put these together, but it is very rewarding if it helps even one person out.
Have you seen cyclejs? Didn't/hasn't really taken off - possibly because it's too far from the norm. It's a "framework" that suffers the opposite restrictiveness problem to most others - forces you to think functionally
Ah, no hadn't heard of it yet. It looks really interesting from an overview of its docs. Time to try it out someday? Thanks for sharing!
Check out the authors videos about it too - really good
Are you talking about these ones on Egghead? app.egghead.io/playlists/cycle-js-...
Sorry, haven't got the link anymore but there's one where he describes the philosophy behind it
Here
Oh my. It is ultra insightful! Will have to go through it a couple of times to properly appreciate.
Might also like Hyperapp
Thanks!
Very cool article thanks for writing it. I'm also super enthusiastic about FP and it's good that people write content about it 😄
About the section "a. Early Returns" I tend to disagree with you: let's take this code
I generally feel that I would have far more troubles debugging it and understanding it at first glance than a code like this one:
Maybe it's more of a personal preference but I would be super interested to read how people feel about this 👍🏽
PS: sorry for my knowledge on Pokemon types, it has been a long time since I've played any Pokemon game 😅
Haha, thanks. 😊
In the end, I guess the point is to make the code more readable. In your example, for sure, the early returns can look more obvious to read. In many cases, they make people lose the flow and intention of the code.
My own preference would certainly depend upon the specific case under consideration, but this was a piece of general advice I have received from many throughout my journey.
Anyway, the main idea of mentioning early returns in the article was to explain that they exist and can be used as an exit from a function (as a function output), but if they complicate the readability too much, it's better to have a single return.
Even my Pokémon knowledge is rusty now. Looking forward to the Diamond and Pearl remakes, and Pokémon Legends. :D
Hope you'll stick around for more! Take care!
Thanks for the answer, I agree we always need to be cautious about readability !
I always like to challenge my knowledge and the things I do without even thinking about them, it's cool to read some interesting articles that help me do so 👍🏽
Waow, what a great article. I'm a teacher and this will greatly help some of my students which want to improve in JS.
Some returns to improve it :
Thanks a lot for this great work, have a nice day :)
Thanks! Glad you liked it!
And also thank you for your feedback. There was really no reason for me to prefer var over let, it was just my own habit. The outputs/returns could use some improvement though. I am looking into better ways to inject executable code into an article, so it could be of more help. Right now the best option seems to be CodePen. I will revisit and update all previous articles once I am satisfied.
Well, stay tuned for more! Thanks again!
Pure functions have no side effects yes. That does not mean that "implicit output" is a side effect. Pure functions have as first rule: the same input gives the same output. (That's the important part)
Implicit outputs is also not a kind of style. it's just lazy. And a bad programming. You working with globals and that could be a real problem in real world. You should more clarify that, because for beginners it looks some kind of cool. And wow its easy. But its the opposit, the code get fast messy and working with other developers would be hard.
But realy nice you are writing about functional programming. And im looking forward to read more. You should go on: "Curry and Function Composition" in some of your next chapters. They are the real deal and helpful af.
Yep, thanks for mentioning that. I think I accidentally glossed over this, because the article was already getting too long.
I thought of covering Pure Functions and Side Effects very properly in the next one, after introducing relevant terms here in this one to aid in understanding the upcoming concepts.
Will be definitely going over Composition and Currying in a later one!
Thanks a lot for liking it!
Thanks, that was a good intro. JavaScript I've found is really a good way to learn functional programming. it allows you to slowly integrate the style into your day-to-day.
The funny thing is that the more I converted to using functional JavaScript the more I was able to understand a more completely functional language like Clojure. As ClojureScript is a variant that compiles to JavaScript and can use JavaScript libraries I am now wondering what really is the point anymore of writing JavaScript at all?
Haha, I once had to contribute to a project written in ClojureScript long ago, for a bounty. Back then, I didn't have much understanding of FP, so I was absolutely blown away! Eventually, I got the hang of it, and I'm looking forward to making something of my own out of it! But it was probably the steepest learning curve of my life, so far.
I was going to bring it up eventually, in one of the articles to come, about how exceedingly amazing FP implementation can be in ClojureScript, for someone coming from a JavaScript or similar background.
JavaScript on its own, in my opinion, has a sweet balance between imperative and declarative styles, hence quite amazing for learning any new concepts.
Thanks for liking the article! There's so much to cover under the umbrella of "fundamentals", it's no wonder many learners are flabbergasted when they are directly skipped over to some advanced FP concept.
Hope you'll like the next one too!
Man, this article is pure gold! It should be in a curated list for anyone who uses JS! I have not finished it, though. Is there any particular reason for the use of "var" over "let" or "const" in your samples provided?
Thanks! I appreciate it.
Choosing "var" / "let" / "const" wasn't really relevant to the concepts being explained, so I just went with the simple "var". No particular reason for it.
Great article, looking forward to the next chapter!
I love FP - there's a great podcast by a guy called Eric Normand which is on Spotify which got me into it.
Thanks a lot! :)
Oh, I'll check the podcast out too. Maybe there'll be a reference from it next article?
It’s called “Thoughts on Functional Programming” if you do search for it.
Yep, found it! Pretty good, thanks!
Of all development and programming-related platforms, I didn't think there'd be something like this on Spotify, haha! 😆
There is a mistake in your test case. f(12) should clearly return 13.
Yep, you are right! Thanks a lot!
Very detailed explanation, even though FP has some of kind of steep learning curve, but it is definitely worth mastering if developers want to dive more. Thanks for the effort.
Glad you liked it! Thank you!
Thanks! Hope it helped just a little bit, atleast!
Some comments may only be visible to logged-in visitors. Sign in to view all comments.