DEV Community

loading...
Cover image for Introduction to Functional Programming

Introduction to Functional Programming

sayuri55987206 profile image Sayuri ・2 min read

In Functional Programing, we want express our whole program in terms of functions.
Functional Programing is Declarative. Which means we focus more on ** what to do ** instead of How to do

First lets understand why Functional Programming is so important.
Functional Programming enables us to

  • Write re-useable code.
  • Debug easily.
  • Read better.

Functions are 1st Class Citizens
because functions can be :

  • Assigned to variables.
  • Can be added to objects and arrays as well .
  • Sent to other functions as a argument.
  • Can be Returned from other functions.

Let's get right into it.

Non Functional Way

let name = "Sayuri" ;
let message = "Hey, fellow devs, I am " ;
console.log(message + name)

---> Hey, fellow devs, I am Sayuri
Enter fullscreen mode Exit fullscreen mode

Functional Way

function message(name) {
    return "Hey, fellow devs, I am " + name ;
}

message("Sayuri")

---> Hey, fellow devs, I am Sayuri
Enter fullscreen mode Exit fullscreen mode

--> Pure Functions

A Pure Function is a function which,
Given the same input, will always return the same output.

A Pure Function :

  • Takes in at least 1 parameter.
  • Return Something (A value or a function).
  • Does not mutates any arguments.

Not Pure

let name = "Sayuri" ;

function message(){
    console.log("Hey, fellow devs, I am " + name )
} 
Enter fullscreen mode Exit fullscreen mode

The above code is not pure because

  • --> It is not taking name as an parameter.
  • --> It's dealing with something in the global scope.
  • --> Also it not having a return value.

Pure Functions have no side effects which means it cannot alter anything outside the function.

Pure Function

function message(name) {
   return "Hey, fellow devs, I am " + name
}
Enter fullscreen mode Exit fullscreen mode

Higher Order Function

A higher order function is a function that takes a function as an argument, or returns a function or does both.

const greet = function takeName (name){
    return function message(msg){
        return msg  + name 
    }
}

greet("Sayuri ")("Hey, fellow devs, I am ")

--> Hey, fellow devs, I am Sayuri
Enter fullscreen mode Exit fullscreen mode

Immutable Code

Immutability means can't be changed.

Mutation --> (Bad)

const code= [ "Javascript", "Python", "React" ]
code[ 2 ] = "Node"
console.log(code)

--> [ "Javascript", "Node", "React" ]
Enter fullscreen mode Exit fullscreen mode

Immutation

const code = [ "Javascript", "Python", "React" ]
const code2 = code.map(lang=> {
  if(lang=== 'Python') {
    lang= 'Node';
  }
  return lang;
});

console.log(code2)

--> [ "Javascript", "Node", "React" ]
Enter fullscreen mode Exit fullscreen mode

Last but not the Least
Do not Iterate using for or while/loops --> Use Map, Reduce, Filter etc.

Let me your thoughts.

Discussion (12)

pic
Editor guide
Collapse
lukeshiru profile image
△ LUKE知る • Edited

Hi Sayuri! 3 things worth mentioning:

  • In dev.to you can get syntax highlight in your code by doing triple back-tick followed by the language name, for example '''javascript (change the ' with back-ticks).
  • In JavaScript we have arrow functions, which make FP a breeze. Taking your HOC example as a base:
const greet = name => msg => `${msg}${name}`;

greet("Sayuri ")("Hey, fellow devs, I am "); // "Hey, fellow devs, I am Sayuri"
Enter fullscreen mode Exit fullscreen mode
  • The immutation example can be achieved with Array.prototype.slice instead of Array.prototype.map, which avoids looping over the entire array to change a single value:
const code = ["Javascript", "Python", "React"];
const findAndReplace = value => replacement => source => {
  const index = source.indexOf(value);
  return index >= 0
    ? [
        ...source.slice(0, index),
        replacement,
        ...source.slice(index + 1)
      ]
    : source;
};
const replacePythonWithNode = findAndReplace("Python")("Node");

console.log(replacePythonWithNode(code)); // [ "Javascript", "Node", "React" ]
Enter fullscreen mode Exit fullscreen mode

EDIT: The performance of this last approach is kinda the same as map. If your concern is about performance, then this is quite better:

const code = ["Javascript", "Python", "React"];
const findAndReplace = value => replacement => source => {
  const index = source .indexOf(value);
  return index >= 0
    ? Object.assign([...source], { [index]: replacement })
    : source;
};
const replacePythonWithNode = findAndReplace("Python")("Node");

console.log(replacePythonWithNode(code)); // [ "Javascript", "Node", "React" ]
Enter fullscreen mode Exit fullscreen mode

Thanks Lukáš Zahradník for poiting that out :D

Collapse
lukaszahradnik profile image
Lukáš Zahradník

The immutation example can be achieved with Array.prototype.slice instead of Array.prototype.map, which avoids looping over the entire array to change a single value:

Well the author is looping over the array only once, but you loop over it once as well because of indexOf and then you slice and spread whole array which you can count as looping over the whole array as well (?). Looks like your way is worse to do it.

Collapse
lukeshiru profile image
△ LUKE知る • Edited

Not quite...

  1. Array.prototype.indexOf stops once the index is found, Array.prototype.map goes over the entire array. In the ideal scenario is in the index 0 and stops, in the worst scenario is the same as map.
  2. Array.prototype.slice doesn't loop over the array, is far more performant than that.
  3. If you don't like to use Array.prototype.slice, you can also use Object.assign like this:
const code = ["Javascript", "Python", "React"];
const findAndReplace = value => replacement => source => {
  const index = source .indexOf(value);
  return index >= 0
    ? Object.assign([...source], { [index]: replacement })
    : source;
};
const replacePythonWithNode = findAndReplace("Python")("Node");

console.log(replacePythonWithNode(code)); // [ "Javascript", "Node", "React" ]
Enter fullscreen mode Exit fullscreen mode

My main point with why you quoted is that the idea with Array.prototype.map is to map over all the values in an array. To change a single value there are better approaches without looping over the entire array.

Thread Thread
lukaszahradnik profile image
Lukáš Zahradník

Is that really a valid point? Both indexOf and map in those cases are O(n). Sure, slice doesn't "loop" over an array, but it creates new copy which is again O(n) operation, same for spread.

Your new version looks better, if there wasn't missing indexOf ofc.

Also, question is if it should replace all items with the value or just one.

Thread Thread
lukeshiru profile image
△ LUKE知る • Edited

You're right, I checked and the performance of my first approach in some scenarios is better, and in some others is the same or even worse. The second one is faster to both map and indexOf+slice. Still my main concern as I expressed previously is using a function meant to map all the elements of an array to just change the value of 1. I didn't checked the actual performance of this and it was kinda surprising, so thanks for pointing that out :D

Thread Thread
lukaszahradnik profile image
Lukáš Zahradník

Agree, I don't find using map for it to be the best and cleanest (kinda misuse of map to be fair). Your second solution is probably the way to go. I don't know if there are better approaches.

Sometimes it's hard to speculate about performance, because spread, spread and indexOf is probably optimized a lot.

Collapse
cappe987 profile image
Casper
let name = "Sayuri" ;
let message = "Hey, fellow devs, I am " ;
console.log(message + name)
Enter fullscreen mode Exit fullscreen mode

Do you consider this non-functional because it's all written in the global scope? Because I don't really see anything else that would make it non-functional. It doesn't mutate and doesn't access variables in an outer scope (since there is none). I would say it's completely functional.

function greet(){
    let name = "Sayuri" ;
    let message = "Hey, fellow devs, I am " ;
    console.log(message + name)
}
Enter fullscreen mode Exit fullscreen mode

Is this still non-functional? Impure functions are still allowed in functional programming btw. But should be kept to a minimum.

A pure function also doesn't have to take an argument. Although if it doesn't it's just a constant function, always returning the same value. But by definition, it is still pure.

Collapse
jackmellis profile image
Jack

Agreed. I can only assume that first example because it's logging to the console (side effect).

Yes there can be minimal impure functions because otherwise your code would do nothing. But I'd say if a function is impure, you should look for a way to make it pure, and only leave it impure as a last resort, most of the time function composition/partial application is the key.

Your greet function I would pass the console in as a parameter. Even better would be to create an abstraction over logging to the console so your function isn't coupled to the console implementation!

Collapse
cappe987 profile image
Casper

Yes of course you could improve the function. I just put his code in a function to show as example.

Collapse
andi1984 profile image
Andreas Sander

I can recommend you watching this video by Anjana Vakil youtube.com/watch?v=e-5obm1G_FY

Collapse
wagslane profile image
Lane Wagner

Great write up :) I recently released an interactive course on the subject: qvault.io/intro-to-functional-prog...