Functional (Programming) mindset

LeoLanese
16.4K views

Functional Programming: What? and Why?

"A journey of a thousand miles begins with a single step." ~ Lao Tzu

What is Functional Programming?

Functional Programming Definition

"Functional programming is a 'declarative' 'paradigm' of building software by 'composing' 'pure functions', avoiding 'shared state', 'mutable data' and 'side-effects'. Placing the mayor emphasis on the use of functions to come up with a result; the goal, rather, is to 'abstract control flows and operations on data with these functions and threaten them as building blocks' by relying on 'JS first-class' and 'higher-order functions' to improve the modularity, predictability and reusability of your code.

So, FP essencially boils down to:

- FP is about pulling programs apart and reassembling them from the same parts, composing in functions together and that means we need to make the output of a function to serve as the input of the next one, in order to do so, we should avoid shared mutable state & side-effects (use pure functions)

"declarative"

FP is a declarative paradigm software development style, like other: IP or OOP, thats **keeps 'functions' and 'data' separate**

In simple terms, it is a way of thinking about software construction, based on some development style that follow principles.

"composing"

Composition means that we can attach multiple functions together, in a chain, where the return value of the first function becomes the input for the next function

Function Composition

Compose

Compose f(g(x)), has a companion funcion: pipe, also we have RxJS Pipe operator (used by Angular6, etc)

Compose, pipe and RxJS Pipe operator
• Compose and pipe are similar. What is change is the order:
• compose: evaluates inside out, <-right-to-left ordown-top.
• pipe: evaluates outside in, left-to-right-> or top-down.
• RxJS pipe method (rxjs/Rx 5.5+ pipeable operators) These operators are pure functions that return the Observable result of all of the operators having been called in the order they were passed in. This can be used as standalone operators instead of methods on an observable.
Compose and pipe example

If you want to compose two functions we can write a compose function:

LodashFP or use the already available ones in libraries such as LodashFP and Ramda

Compose example using TypeScript
// When multiple decorators apply to a single declaration, their evaluation is similar to function composition in TS
function f() {
console.log("f(): evaluated");
return function (target, propertyKey: string, descriptor: PropertyDescriptor) {
console.log("f(): called");
}
}
function g() {
console.log("g(): evaluated");
return function (target, propertyKey: string, descriptor: PropertyDescriptor) {
console.log("g(): called");
}
}
function h() {
console.log("h(): evaluated");
return function (target, propertyKey: string, descriptor: PropertyDescriptor) {
console.log("h(): called");
}
}
class C { // some as: f(g(h(x)))
@h()
@f()
@g()
}
// In this model, when composing functions f,g and h the resulting composite (f ∘ g ∘ h)(x) is equivalent to f(g(h(x))).
// 1) The expressions for each decorator are evaluated top-to-bottom.
// h(): evaluated
// f(): evaluated
// g(): evaluated

// 2) The 'results are then called as functions' from bottom-to-top.
// g(): called
// f(): called
// h(): called


Execure TS code (JSfiddle)

RxJS Pipe method example
// old way RxJS 5.5-
import { from } from 'rxjs/observable/from';

const source$= from([1, 2, 3, 4, 5, 6, 7, 8, 9]); source$
.filter(x => x % 2)
.map(x => x * 2)
.scan((acc, next) => acc + next, 0)
.startWith(0)
.subscribe(x => console.log(x))

// new way RxJS 5.5+ pipeable operators & Angular6+
import { Observable, pipe } from 'rxjs/Rx';
import { filter, map, reduce } from 'rxjs/operators';

// our custom pure functions operators: nice & easy!
const filterOutEvens = filter(x => x % 2) // custom using filter
const doubleBy = x => map(value => value * x); // custom using map
const sum = reduce((acc, next) => acc + next, 0); // custom using reduce

const complicatedLogic = pipe(
filterOutEvens,
doubleBy(2),
sum
);

const source$= Observable.range(0, 10); // Generates an observable sequence of integral numbers within a specified range // compose a bunch of pure function operators & pass them as a single operator to an observable source$
.let(complicatedLogic)
.subscribe(x => console.log(x)); // 50


"pure functions"

A pure function is a function which:

• Given the same input, always return the same output.
• Has no side-effects (immutable)

Pure functions are tested by building a table of input values and output expectations.

"shared state"

FP avoids shared state: is stateless. Instead relying on immutable data structures and pure calculation. Thanks to this, functions always give the same output for a given input (the outcome of a function is dependent only on the input and nothing else)

Sharing State problems:

• Change order:The problem with shared state is that in order to understand the effects of a function, you have to know the entire history of every shared variable that the function uses or affects.
• Race-condition: A common bug associated to 'share state'is 'race-condition'

With shared state, the order in which function calls are made changes the result of the function calls:

Calling x1(), x2()

This example is exactly equivalent to the above, except the order of the function calls is reversed

Calling x2(), x1()

Better avoid shared state, the timing and order of function calls: don’t change the result of calling the function

Avoid shared state = Order it is not important

"mutable data"

An mutable object is any object which can be modified after it's created.

"immutable"

An immutable value or object cannot be changed, so every update creates new value, leaving the old one untouched.

For example, if your application state is immutable, you can save all the states objects in a single store to easily implement undo/redo functionality

"side-effects"

Mutating data can cause unintended side-effects.

A side effect is a change of system state or observable interaction with the outside world that occurs during the calculation of a result.

Side effects may include (but not limited to)

• Change state
• Anything that rely on current time, it is impure.
• Anything that rely on random number
• Changing the filesystem
• Inserting a record into a database
• Making an http call
• Modifying the DOM tree
• Accessing system state
• I/O interaction (user intput, disk access, network access, printing to the screen) is impure throws
// impure function due to use of external non-constants
// The impure function indirectly depends on x
// If you were to change x, then addx would output a different value for the same inputs.
let x = 10
const addx = (a) => a + x

// also impure due to side-effect
const setx = (v) => x = v
`

** abstracting control flows and operations on data with these functions and threaten them as building blocks**

Abstractions hide details (abstract me of the detail) and give us the ability to talk about problems at a higher (or more abstract) level.

"First-Class-functions" (FcF)

Functions in JavaScript are treated as objects, not just methods: mean that you can STORE functions into a 'variable':

First-Class

The "first-class" means that 'something' has a 'value'

First-Class-function

"First-Class Functions” mean that you can STORE functions into a variable

"Higher-order-functions" (HoF)

In JS, functions are 'First-Class' & 'Higher-Order functions'

Functions are objects: Not just methods: mean that you can STORE functions into a variable, they can be passed around as data, can appear as parameters to other functions (these are usually known as callbacks), and can be returned from other functions (which leads to things like Composable Functions)

This allow us to have Function Composition: The fact that we can take a function and put into another function, allow us to compose a lot of small functions into bigger functions.

Why?

Benefits of Functional Programming:
• Functions Stateless: With Pure functions, functions doesn’t have an internal state. It means that all operations it performs are not affected by that state and given the same input parameters and produces the same deterministic output.
• Deterministic: The great benefit of pure functions is that their output is deterministic: given an input it will always return the same value. This characteristic makes them extremely easy to debug.
• Improve the modularity and Reusability: FP treats functions as building blocks by relying on: first-class, higher-order functions to improve the modularity and reusability of your code.

• Predictability side effects free => Why? Much easer to understand and predict the program behaviour

• Easy to debug Due to active avoidance of data mutation.

• Minimizing parts The logic is minimal: less logic = less bugs.

• Declarative Declarative rather than imperative code (what to do, rather than how to do it)

• Functional oriented Function composition over imperative flow control

GO TO TOP