Functional Programming

Stateless

Pure

Functors

Monoids

High Order Functions

Immutability

Lazy Evaluation

Curring

Side Effect

Predict

Lambda

Folding

Arity

Idempotent

Setoid

Pattern Matching

Recursion

Immutability

First-Class Functions

Declarative Programming

Side Effects

Recursion

Tail Call Optimization

Pattern Matching

Memoization

"Functional programming (FP) is a programming paradigm — a style of building the structure and elements of computer programs — that treats computation as the evaluation of mathematical functions and avoids changing-state and mutable data"

"Object-oriented programming (OOP) is a programming paradigm based on the concept of “objects”, which may contain data, in the form of fields, often known as attributes; and code, in the form of procedures, often known as methods.”

Procedural programming is a programming paradigm, derived from structured programming, based upon the concept of the procedure call. Procedures, also known as routines, subroutines, or functions, simply contain a series of computational steps to be carried out.”

Where do we find it?

React & Redux

Immutable.js

Elm

Lisp

Lisp

Lowdash-fp

Haskell

// --- FP UTILITIES (The "Engine") ---
// Combines functions from right to left: f(g(x))
const compose = (...fns) => (x) => fns.reduceRight((v, f) => f(v), x);

// Curried helpers for point-free style
const map = (f) => (arr) => arr.map(f);
const filter = (f) => (arr) => arr.filter(f);
const prop = (key) => (obj) => obj[key];
const reduce = (f, initial) => (arr) => arr.reduce(f, initial);
const sortBy = (f) => (arr) => [...arr].sort((a, b) => f(b) - f(a));

// --- DOMAIN LOGIC ---
const getTags = prop('tags');
const isPopular = (item) => item.viewCount > 1000;
const toUpperCase = (str) => str.toUpperCase();

// A function to count occurrences of tags: ['a', 'b', 'a'] -> {a: 2, b: 1}
const countOccurrences = reduce((acc, tag) => ({
  ...acc,
  [tag]: (acc[tag] || 0) + 1
}), {});

// --- THE COMPLICATED PART: THE PIPELINE ---
// We define the logic WITHOUT mentioning the data (Point-Free)
const getTopTrendingTags = compose(
  (obj) => Object.entries(obj), // 5. Convert back to array for sorting
  countOccurrences,             // 4. Count them
  map(toUpperCase),             // 3. Normalize strings
  (arr) => arr.flat(),          // 2. Flatten nested tag arrays
  map(getTags),                 // 1. Extract tags from objects
  filter(isPopular)             // 0. Only keep popular posts
);

// --- EXECUTION ---
const rawData = [
  { id: 1, tags: ['js', 'fp'], viewCount: 2500 },
  { id: 2, tags: ['js', 'react'], viewCount: 500 }, // Ignored (low views)
  { id: 3, tags: ['fp', 'haskell'], viewCount: 1200 },
];

console.log(getTopTrendingTags(rawData)); 
// Output: [ ["FP", 2], ["JS", 1], ["HASKELL", 1] ]

First let's take a look at what it looks like...

// A simple "Identity" wrapper
const Box = x => ({
  map: f => Box(f(x)),           // Apply a function to the value inside
  fold: f => f(x),               // Extract the value
  inspect: () => `Box(${x})`
});

// Using the Box to safely format a string
const result = Box("  functional programming  ")
  .map(s => s.trim())
  .map(s => s.toUpperCase())
  .map(s => s.split(" "))
  .fold(arr => arr.join("-"));

console.log(result); // "FUNCTIONAL-PROGRAMMING"

The Dreaded Monad

What is a Mathematical function?

f(x) = x + x
f(5) = 5 + 5

(Domain)
תְּחוּם הַגְדָרָה

(Range)
תְּחוּם הַפֵּרוּשׁ\טווח

The notion of "pure" functions

f(x) = x + 10;
f(x, y) = (x * y) * 17.1

 

  • Race condition
  • ...leads to
  • Complexity
  • ...leads to
  • Unpredictability

Side Effects

State Management

How many times did we do this?

let value = 1;

function timesByTwo() {
    value = value * 2;
    return value;
}

Not predictable, Hard to test

console.info(timesByTwo()); -> 2
console.info(timesByTwo()); -> 4
....

class BenefitsManagerService {
    constructor(private user: User) { }
    applyBenefits() {
        this.currentUser.age > 66
            ? (this.user.benefitsPoints += 10)
            : (this.user.benefitsPoints += 2);
    }
}

Imperative
vs
Declarative

Programming Paradigms

Imperative

Declerative

Outline in the code how to do something.

It means to give it instructions (how).

Declare the intent

It means to say what you want to achieve (not how).

 

Can someone give me an example of a declarative language?

Programming Paradigms

Impertive (...how to do)

Declerative (...what to achive)


if(!precincts.containsKey(Cities.NEW_YORK)) {
    precincts.put(Cities.NEW_YORK, new PolicePrecinct());
}

precincts.computeIfAbsent(Cities.NEW_YORK, name -> new PolicePrecinct());

Programming Paradigms

Impertive (...how to do)

Declerative (...what to achive)

for(let i=0; i<students.length; ++i){
	console.info(students[i]);
}
students.forEach(console.info);

Programming Paradigms

Impertive (...how to do)

Declerative (...what to achive)

function doubleNumbers(numbers) {
    const doubled = [];
    for (let i = 0; i < numbers.length; ++i) {
        doubled.push(numbers[i] * 2);
    }
    return doubled;
}

doubleNumbers([1, 2, 3]); //2, 4, 6
[1, 2, 3].map(number => number *2);

const doubleIt = number => number * 2;

[1, 2, 3].map(doubleIt);

Programming Paradigms

Impertive (...how to do)

Declerative (...what to achive)

const authenticate = form => {
  const user = toUser(form);
  return logIn(user); 
};
const authenticate = compose(toUser, logIn);

Race condition example

// ['Clark Kent', 'James J\'onzz', 'Diana Prince', 'Hal Jordan'....];
const heros = await fetchHerosByCompanyName('DC') 
const justiceLeague = [];

function provisionHeros () {
    for(hero of heros) {
        if(!justiceLeague.includes(hero)) {
            justiceLeague.push(hero);
        }
    }
    console.info(justiceLeague);
}
const listOfSuspects = await featchSuspects();
listOfSuspects
    .map(extractPertinentData)
    .filter(byProximety)
    .take(3);

map()

result

filter()

take()

Tail call Optimization

const listOfSuspects = await featchSuspects();
listOfSuspects
    .map(extractPertinentData)
    .filter(byProximety)
    .take(3);

map()

take()

Tail call Optimization

Tail call Optimization

  • Supporting
    • Lisp
    • Haskel
    • Erlang / Elixir
    • Scala
  • It's "complicated" list
    • JavaScript specs call for this - but only Safari/Webkit does, V8 does not
    • C / C++ / Rust - Only on compile time, NOT runtime
  • Rejects the concept
    • Java
    • Python

Function is a First Class Citizen

  • A function is a function
  • A function is a variable
  • You can pass functions around as arguments
  • This is a very powerfull concept

This means...

Example

function adderCreator(first) {
    return function (second) {
        return first + second;
    }
}

const add5 = adderCreator(5);

console.info(add5(1)) // 6
console.info(add5(10)) // 15

////es6
const adderCreator = first => second => first + second;

This is called: Curring

Currying is the process of taking a function with multiple arguments and returning a series of functions that take one argument and eventually resolve to a value (Currying doesn't call a function; it just transforms it).

Curring

Partial

application

const actualHttpClient = async (baseUrl, apiKey, endpoint) => {
  // Use URL constructor to avoid slash bugs
  const url = new URL(endpoint, baseUrl).href;
  try {
    const response = await fetch(url, {
      headers: { 'x-api-key': apiKey },
    });
    
    if (!response.ok) throw new Error(`HTTP error! status: ${response.status}`);
    return await response.json();
  } catch (error) {
    console.log(error);
    throw error; 
  }
};
// Generic Partial Application (works for sync and async)
const partial = (fn, ...fixedArgs) => (...remainingArgs) => 
  fn(...fixedArgs, ...remainingArgs);

const apiBaseUrl = 'https://jsonplaceholder.typicode.com/';
const apiKey = 'very-secret-api-key-here';
// Create specialized function
const apiClient = partial(actualHttpClient, apiBaseUrl, apiKey);

(async () => {
  try {
    const todo = await apiClient('todos/1');
    console.info('Success:', todo);
  } catch (err) {
    console.error('Caught in implementation:', err.message);
  }
})();

Curring

const aGenericFunction = (one, two, three) => one + two + three;
console.info(aGenericFunction(1, 2, 3)); //6
const curry = (func) =>  {
  return curried = (...args) => {
    if (args.length >= func.length) {
      return func.apply(this, args);
    } else {
      return (...args2) => {
        return curried.apply(this, args.concat(args2));
      }
    }
  };
}
const aCurriedFunction = curry(aGenericFunction);

This is a Control Flow

console.info(aCurriedFunction(1, 2, 3)); //still 6
console.info(aCurriedFunction(1)(2, 3)); //curring the 1st argument - result is still 6
console.info(aCurriedFunction(1)(2)(3)); //curring all way - result is still 6

Curring

It's weired....why do I need it?

const actualHttpClient = async (baseUrl, apiKey, endpoint) => {
  // Use URL constructor to avoid slash bugs
  const url = new URL(endpoint, baseUrl).href;
  try {
    const response = await fetch(url, {
      headers: { 'x-api-key': apiKey },
    });
    
    if (!response.ok) throw new Error(`HTTP error! status: ${response.status}`);
    return await response.json();
  } catch (error) {
    console.log(error);
    throw error; 
  }
};
// Generic Partial Application (works for sync and async)
const partial = (fn, ...fixedArgs) => (...remainingArgs) => 
  fn(...fixedArgs, ...remainingArgs);

const apiBaseUrl = 'https://jsonplaceholder.typicode.com/';
const apiKey = 'very-secret-api-key-here';
// Create specialized function
const apiClient = partial(actualHttpClient, apiBaseUrl, apiKey);

(async () => {
  try {
    const todo = await apiClient('todos/1');
    console.info('Success:', todo);
  } catch (err) {
    console.error('Caught in implementation:', err.message);
  }
})();

Purity


[1, 2, 3].splice(1) // [2, 3] -> Not Pure
[1, 2, 3].slice(1) // [2,3]	-> Pure

https://github.com/MostlyAdequate/mostly-adequate-guide

Summery

Functional Programming – Characteristics

 

  • FP languages are designed on the concept of mathematical functions that use conditional expressions and recursion to perform computation.

  • FP supports higher-order functions and lazy evaluation features.

  • FP languages don’t support flow control constructs like loops and conditional statements (If-Else and Switch). They use the functions and function calls directly.

    • If-Else -> Ternary operator

    • Switch -> Map<type, function>

  • Like OOP, functional programming languages support popular concepts such as Abstraction, Encapsulation, Inheritance, and Polymorphism.

 const userMerit = user.department === 'r&d' ? giveMuchoMoney() : ignoreRequest();
const noop = () => {};
const possibleOperations = new Map();
possibleOperations.set('r&d', giveMochoMoney);
possibleOperations.set('product', giveHalfMondyFromRnd);
possibleOperations.set('marketing', throw504);

const newSalaryByDepartment = possibleOperations.has(user.department) 
	? possibleOperations.get(user.department) 
	: noop;

const merit = newSalaryByDepartment(user);

No If-Else

No Switch

Functional Programming – Advantages

  • Bugs-Free Code − Functional programming does not support state, so there are no side-effect results and we can write error-free codes.

  • Efficient Parallel Programming − Functional programming languages have NO Mutable state, so there are no state-change issues. One can program "Functions" to work parallel as "instructions". Such codes support easy reusability and testability.

  • Efficiency − Functional programs consist of independent units that can run concurrently. As a result, such programs are more efficient.

  • Lazy Evaluation − Functional programming supports Lazy Functional Constructs like Lazy Lists, Lazy Maps, etc.

Functional Programming OOP
FP uses Immutable data OOP uses Mutable data
Follows Declarative Programming based Model Follows Imperative Programming Model
What it focuses is on: “What you are doing in the program.” What it focuses is on “How you are doing your programming.”
Its functions have no-side effects Method can produce many side effects
Flow Control is performed using function calls & function calls with recursion Flow control process is conducted using loops and conditional statements
Supports both “Abstraction over Data” and “Abstraction over Behavior.” Supports only “Abstraction over Data”.

Summery

theEnd(now) => new End

Functional Programing

By Eyal Mrejen

Functional Programing

  • 196