·
Notes from Functional JavaScript First Steps lections
Contents

## Pure functions

### Avoid side effects

Do nothing but return output based on nothing but input.

#### Imperative

```let name = "Alonzo";
let greeting = "Hi";

console.log(`\${greeting}, \${name}!`);
// Hi, Alonzo!

greeting = "Howdy";
console.log(`\${greeting}, \${name}!`);
// Howdy, Alonzo!```

#### Functional

```function greet(greeting, name) {
return `\${greeting}, \${name}!`;
}

greet("Hi", "Alonzo");
// "Hi, Alonzo!"

greet("Howdy", "Alan");
// "Howdy, Alan!```

#### Side effects

```let thesis = { name: "Church's", date: 1936 };

function renameThesis(newName) {
thesis.name = newName;
console.log("Renamed!");
}

renameThesis("Church-Turing"); // Renamed!
thesis; //{name: "Church-Turing", date: 1936}```

#### No side effects

```const thesis = { name: "Church's", date: 1936 };

function renameThesis(oldThesis, newName) {
return {
name: newName,
date: oldThesis.date,
};
}

const thesis2 = renameThesis(thesis, "Church-Turing");
thesis; // {name: "Church's", date: 1936}
thesis2; // {name: "Church-Turing", date: 1936}```

## Recursion

• Iteration -- imperative, looping, stateful
• Recursion -- functional, self-referential, stateless

Some examples of achieving the same effect through iteration and recursion.

#### Iteration

```function sum(numbers) {
let total = 0;
for (i = 0; i < numbers.length; i++) {
total += numbers[i];
}
}

sum([0, 1, 2, 3, 4]); // 10```

#### Recursion

```function sum(numbers) {
if (numbers.length === 1) {
// base case
return numbers;
} else {
// recursive case
return numbers + sum(numbers.slice(1));
}
}

sum([0, 1, 2, 3, 4]); // 10```

#### Iteration

```function iterativeFibonacci(n) {
if (n === 0) return 0;
if (n === 1) return 1;

let previous = 0;
let current = 1;
for (let i = n; i > 1; i--) {
let next = previous + current;
previous = current;
current = next;
}
return current;
}```

#### Recursion

```function recursiveFibonacci(n) {
if (n === 0) return 0;
if (n === 1) return 1;
return recursiveFibonacci(n - 2) + recursiveFibonacci(n - 1);
}```

## Higher-order function

The higher-order functions `filter()`, `map()`, and `reduce()` are three of the most useful tools in a functional programmer's toolbox. Let's dig into how they work & how to use them.

Link to my fork of exercises on Observable: https://observablehq.com/d/3003212404713bcf

#### Filter

The filter function takes a "predicate" function (a function that takes in a value and returns a boolean) and an array, applies the predicate function to each value in the array, and returns a new array with only those values for which the predicate function returns true.

Here's a recursive implementation of the `filter()` function:

```function filter(predicateFn, array) {
// base case
if (length(array) === 0) return [];
// recursive case
const filteredFirst = predicateFn(firstItem) ? [firstItem] : [];
return concat(filteredFirst, filter(predicateFn, tail(array)));
}```
```wholes = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
greaterThanFour = filter(
(n) => n > 4,
wholes,
);
// greaterThanFour is [5,6,7,8,9,10]```

#### Map

The map function takes a one-argument function and an array, and applies the function to each element in the array, returning a new array of the resulting values.

```function map(fn, array) {
// base case
if (length(array) === 0) return [];
// recursive case
const mappedFirst = [fn(first)];
return concat(mappedFirst, map(fn, tail(array)));
}```
```wholes = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
doubled = map((n) => n * 2, wholes);
// doubled is [0,2,4,6,8,10,12,14,16,18,20]```
```wholes = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
fizzBuzz = map((n) => {
const fizz = n % 3 === 0 ? "fizz" : "";
const buzz = n % 5 === 0 ? "buzz" : "";
return fizz || buzz ? fizz + buzz : n;
}, wholes);
// fizzBuzz is [fizzbuzz,1,2,fizz,4,buzz,fizz,7,8,fizz,buzz]```

#### Reduce

The `reduce` function is the odd one of the bunch. Unlike `filter` and `map`, which each take an array and return another array, reduce takes in an array and returns a single value - in other words, it "reduces" an array to a single value.

`reduce` takes three arguments:

• a "reducer" function, which takes two arguments - an accumulator and the next value from the array - and returns a single value. This function will be applied to each value in the array, with the accumulator storing the reduced value so far.
• an initial value, passed to the first call of the reducer function
• the array to reduce
```function reduce(reducerFn, initialValue, array) {
// base case
if (length(array) === 0) return initialValue;
// recursive case
```wholes = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
```max = reduce(