> For the complete documentation index, see [llms.txt](https://mihai-gheorghe.gitbook.io/tic/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://mihai-gheorghe.gitbook.io/tic/functional-programming.md).

# Functional Programming

## Principles

* Separate data from behavior
* Use of declarative functions (as opposed to imperative)
* Proper use of caching (computing efficiency)
* Pure functions
* Composing (chained atomic pure operations)

## Pure functions

* Don't mutate state (global scope)
* Always have a return statement. This is useful for chaining purposes
* Idempotence. On the same input, return the same output, regardless of how many times executed
* Usually have 1 argument

```javascript
//Side effects:
const array = [1,2,3];
function mutateArray(arr) {
  arr.pop()
}
function mutateArray2(arr) {
  arr.forEach(item => arr.push(1
  ))
}
//The order of the function calls will matter.
mutateArray(array)
mutateArray2(array)
array
```

```javascript
// Idempotence:
function notGood() {
  return Math.random()
  // new Date();
}

function good() { //pure function
  return 5
}

Math.abs(Math.abs(10)) //pure function
```

## Cache in memory

```javascript
//Memoization
//learn to cache
function addTo80(n) {
  return n + 80;
}

addTo80(5)

let cache = {};
function memoizeAddTo80(n) {
  if (n in cache) {
    console.log('quickly rerieved from cache');
    return cache[n];
  } else {
    console.log('expensive operation');
    const answer = n + 80;
    cache[n] = answer;
    return answer;
  }
}
```

Here is a better implementation of caching, making the above pure.

```javascript
// let's make that better with no global scope.
function memoizeAddTo80(n) { 
  let cache = {};
  return function(n) { //This is closure in javascript.
    if (n in cache) {
      console.log('quickly rerieved from cache');
      return cache[n];
    } else {
      console.log('expensive operation');
      const answer = n + 80;
      cache[n] = answer;
      return answer;
    }
  }
}

const memoized = memoizeAddTo80();
console.log(1, memoized(6))
// console.log(cache)
// console.log('-----------')
console.log(2, memoized(6))
```

## Currying and Composing

**Currying** in JavaScript transforms a function that takes multiple arguments into a sequence of functions, each taking a single argument. For example, a function `f(a, b)` becomes `f(a)(b)`. It allows partial application of functions, where you can fix some arguments and pass others later, enabling more flexible function usage.

```javascript
// add two numbers
const add = a => b => a + b;

//similar to
const add2 = a => {
    return b => {
        return (a + b)
        }
    }

const result = add(2)(3); // => 5
```

### pipe() and compose()

Composing is the process of chaining functions. In other words, through `pipe()` and `compose()` we create a pipeline of functions with the output of one function connected to the input of the next. This is the reason for which these functions need to be pure.

{% tabs %}
{% tab title="chaining functions" %}

```javascript
//as seen on freecodecamp.org/news/pipe-and-compose-in-javascript-5b04004ac937/

//Let’s write a function that returns someone’s name.
getName = (person) => person.name;
getName({ name: 'Buckethead' });
// 'Buckethead'

//Let’s write a function that uppercases strings.
uppercase = (string) => string.toUpperCase();
uppercase('Buckethead');
// 'BUCKETHEAD'

//What if we want to add a function that gets the first 6 characters of a string?
get6Characters = (string) => string.substring(0, 6);
get6Characters('Buckethead');
// 'Bucket'

//Let’s get really crazy and add a function to reverse strings.
reverse = (string) =>
  string
    .split('')
    .reverse()
    .join('');

reverse('Buckethead');
// 'daehtekcuB'


//chaining all the operations would result in
reverse(get6Characters(uppercase(getName({ name: 'Buckethead' }))));
// 'TEKCUB
```

{% endtab %}
{% endtabs %}

Instead of jamming functions within functions or creating a bunch of intermediate variables, let’s `pipe` all the things!

```javascript
// Function composition enabling pipe functionality using reduce()
const pipe = (...functions) => input => functions.reduce(
    (acc, fn) => fn(acc),
    input
)
```

{% tabs %}
{% tab title="pipe" %}

```javascript
pipe(
  getName,
  uppercase,
  get6Characters,
  reverse
)({ name: 'Buckethead' });
// 'TEKCUB'
```

{% endtab %}
{% endtabs %}

`compose()` is similar, it just deals with the chain in the opposite direction (from right to left).

```javascript
const g = n => n + 1;
const f = n => n * 2;

const h = x => f(g(x))
h(30); //=> 62

const compose = (f, g) => x => f(g(x));
compose(f,g)(30); //=> 62
```
