  ## Hardcore JS Patterns

The payoff of these patterns happens as our app scales.

## Resources

1. FE Masters Course
2. Course Slides
3. What is a semigroup?
4. What is a Set?
5. FP Jargon: Semigroup
6. Monoid Codepen Exercises
7. What are these Math Symbols?
8. Function Modelling Codepen Exercises
9. Fantasy-land figures
11. Daggy GitHub
12. Catamorphisms
14. FP-TS GitHub
15. FP-TS Website

## Introduction

During the introduction, Brian refers to the Domain Driven Design book.

First goal: Functions with defined contracts.

Brian demostracts a "composable contract for this generic function" with the function being `joinWithSpace`:

```.css-e69dqy{position:relative;z-index:0;}.css-qq5p7o{padding:var(--chakra-space-5);border-radius:8px;margin-top:var(--chakra-space-8);margin-bottom:var(--chakra-space-8);background:#011627;-webkit-padding-start:0px;padding-inline-start:0px;-webkit-padding-end:0px;padding-inline-end:0px;overflow:hidden;}const user = { firstName: 'Bobby', lastName: 'Fischer' };
const joinWithSpace = (...args) => args.join(' ');

joinWithSpace(user.firstName, user.lastName);
joinWithSpace('a', 'b', 'c'); // 'a b c'
joinWithSpace(joinWithSpace('a', 'b'), 'c'); // 'a b c'
joinWithSpace('a', joinWithSpace('b', 'c')); // 'a b c'

// becoming even more generic
joinWithSpaces = joinable => joinable.join(' ');

The aim is that we want "highly generalized functions"

## Composition Architecture

When we use composition:

• Satisfy use cases
• Simple, understandable pieces
• Reuse
• Harder to change implementation
• Harder for user to compose

The opposite side when we are not using composition:

• Flexibility in implementation changes
• Less use cases to support
• Flags, is/else
• Won't satisfy all cases
• Less reuse

Note: There is a reason to use both.

## Normalize Effect Types

Monads don't actually compose. Functors compose and monoids compose. We focus on normalizing everything into the one shape.

Normalize effect types throughout the app.

## Semigroups

In computer science, a Semigroup is an algebraic structure that has a set and a binary operation that takes two elements in the set and returns a Semigroup that has an associative operation. Note that the official definition of a Set is an abstract data type that can store unique values, without any particular order, although I believe Semigroups don't require a unique Set.

Closed means that we are going to get the same data type back that we're operating on.

```1 + 2 + 6; // this is associative but also closed meaning we can only use the data type
2 * 5 * 8; // again, closed under data type
10 / 4 / 2; // neither closed nor associative
true && true && false; // associative```

If you are closed and associative, then you are also parallel. This means you could chuck smaller compositions into multiple servers, get the results back and combine and you'll be peaches.

In addition to the official definition of semigroups, in programming a semigroup is an object that has a `concat` function that combines it with another object of the same type.

`.concat(); // [1, 2]`

From the course:

```// semigroups defined
const Sum = x => ({
x,
concat: other => Sum(x + other.x),
});

Sum(3).concat(Sum(5)); // Sum(8)

const Product = x => ({
x,
concat: other => Product(x * other.x),
});

Product(3).concat(Product(5)); // Product(15)

// Any
const Any = x => ({
x,
concat: other => Any(x || other.x),
});

Any(true).concat(Any(false)); // Any(true)

// String Concat
const String = x => ({
x,
concat: other => String(x + other.x),
});

String('hi').concat(String('!')); // String('hi!')```

## Monoids

Monoids are just a semigroup with an "identity"

```// monoids
const Sum = x => ({
x,
concat: other => Sum(x + other.x),
});

Sum.empty = () => 0;
Sum(0).concat(Sum(5)); // Sum(5)
Sum.empty().concat(Sum(5)); // Sum(5)

const Product = x => ({
x,
concat: other => Product(x * other.x),
});

Product.empty = () => Product(1);

Product(1).concat(Product(10)); // Product(10)
Product.empty().concat(Product(10)); // Product(10) - programming to an interface, not a specific value

// Any
const Any = x => ({
x,
concat: other => Any(x || other.x),
});
Any.empty = () => false;

Any.empty().concat(Any(false)); // Any(false)
Any.empty().concat(Any(true)); // Any(true)```

So why does identity matter here? Null values.

In our day-to-day, if I was to run through a list and reduce it down, if you don't have a starting value you will get a `null` or `undefined`, but if you have a starting value then these two correspond to reduce.

```const res1 = [1, 2, 3, 4, 5].map(Sum).reduce((acc, n) => acc.concat(n)); // 15
const res2 = [].map(Sum).reduce((acc, n) => acc.concat(n)); // uh oh! error
const res2 = [].map(Sum).reduce((acc, n) => acc.concat(n), Sum.empty()); // Ahhh safe! We got a zero.```

In practice, we don't need the whole `[1, 2, 3, 4, 5].map(Sum).reduce((acc, n) => acc.concat(n), Sum.empty())` line. If we used something like `List` from immutable JS that has a `foldMap` method, we could run `List([1, 2, 3, 4, 5]).foldMap(Sum, Sum.empty())`.

## Semigroups vs Monoids

Here we show that you cannot promote a semigroup to a monoid with an identity.

```// Note: we cannot actually provide a identity for this.
const Intersection = x => ({
x,
// assume Lodash lib utility in
concat: other => Intersection(_.intersection(x, other.x)),
});```

In the above case, we note that we cannot promote an `Intersection` from a semigroup into a monoid.

## Identity Functor

```// assume types defined elsewhere
const { Id, Task, Either } = require('../types');
const { Left, Right } = Either;

const res = Id.of(Sum(2)).concat(Id.of(Sum(5))); // Id(Sum(5))
console.log(res.extract()); // the same as fold```

Id is a monoid if what it is holding is a monoid.

## Concat Method

Here we look at what it looks like to concat a few functors together:

```// assume types defined elsewhere
const { Id, Task, Either } = require('../types');
const { Left, Right } = Either;

const res1 = Right('hello ').concat(Right('world')); // Right('hello world')
res.fold(console.log, console.log);

const res2 = Right('hello ').concat(Left('arrhhihiuh')); // Left('arrhhihiuh')
res.fold(console.log, console.log);

res.fork(console.log, console.log); // 'hello cruel world'

res.fork(console.log, console.log); // ['hello', 'cruel world']

res.fork(console.log, console.log); // 'error'```

Whenever you concat, make sure you never fall out of the type ie always return the result wrapped in the type.

```const Alternative = x => ({
x,
concat: other => Alternative(other.x.isLeft ? x : x.concat(other.x)),
});

const res = Alternative(Right('hi')).concat(Alternative(Left('bye')));
console.log(res.x.fold(id, id)); // 'hi'

const res = Alternative(Right('hi'))
.concat(Alternative(Right('!!!!!')))
.concat(Alternative(Left('bye')));
console.log(res.x.fold(id, id)); // 'hi!!!!!'

// reducing to be prettier
const res = List([Right('a'), Right('b'), Left('c')]).foldMap(
Alternative,
Alternative(Right('')),
); // mapping into Alternative but also providing the starting point (could be identity)
console.log(res.x.fold(id, id)); // 'ab'

const res = List([Right('a'), Left('b'), Right('c')]).foldMap(
Alternative,
Alternative(Right('')),
); // mapping into Alternative but also providing the starting point (could be identity)
console.log(res.x.fold(id, id)); // 'ac'```

You'll end up making your own monoids more than you'll end up making your own functors.

## Monoid Use Casses

Using it to concat responses from multiple server calls.

```// getting an array of Promises
const getDirectMessages = () => fetch('/dm').then(x => x.json());

getAppAlerts().concat(getDirectMessages()); // Promise([{id: 1, msg: "Policy update"}, {id: 2, msg: 'hi from spain'}])

// map is a way to define a semigroup
const getPost = () =>
fetch('/post')
.then(x => x.json())
.then(Map);
.then(x => x.json())

// thanks to concat, we can assign the comments to the blog post

Concating from files

```const readFile = promisify(fs.readFile);
const filepaths = ['one.txt', 'two.txt', 'three.txt'];

## Creating a Validation Library

First, we go through a basic implementation using Either.

```import List from 'immutable-ext'
import {Either} from '../types'
const {Left, Right} = Either

const isPresent = x => !!x

const validate = (spec, obj) => {
List.(Object.keys(spec)).foldMap(key => {
spec[key](obj[key]) ? Right(obj) : Left(`\${key} bad`)
}, Either.of(obj))
}

const validations = {name: isPresent, email: isPresent}
const obj = {name: 'brian', email: 'brian@brian.com'}
const res = validate(validations, obj) // obj | []

res.fold(console.error, console.log)```

This doesn't really do what we want it to do, so let's make our own `Success` and `Failure` types and these can be a "subclass" of a Validation type.

## Creating Success & Fail Monoids

```import List from 'immutable-ext'
import {Either} from '../types'
const {Left, Right} = Either

const isPresent = x => !!x

const Success = x => ({
x,
isFail: false,
fold: (f, g) => g(x),
concat: other => (other.isFail ? other : Success(x)),
});

const Failure = x => ({
x,
isFail: true,
fold: (f, g) => f(x),
concat: other => (other.isFail ? Fail(x.concat(other.x)) : Fail(x)),
});

const validate = (spec, obj) => {
List.(Object.keys(spec)).foldMap(key => {
spec[key](obj[key]) ? Success(obj) : Failure(`\${key} bad`)
}, Success.of(obj))
}

// just check if both are present for now
const validations = {name: isPresent, email: isPresent}
const obj = {name: 'brian', email: 'brian@brian.com'}
const res = validate(validations, obj) // obj | []

res.fold(console.error, console.log) // [{name: 'brian', email: 'brian@brian.com'}]

const obj2 = {name: 'brian', email: ''}
const res2 = validate(validations, obj2) // obj | []

const obj3 = {name: '', email: ''}
const res3 = validate(validations, obj3) // obj | []

You can then start to weigh up your options about how you want to go about things.

## Creating the Validation Monoid

```// any alternative approach to `isPresent` but loses the key.
const isPresent = Validation(key, x => !!x ? Success(x) : Fail([`\${key} needs to be present`]))

const isEmail = Validation(key, x => /@/.test(x) ? Success(x) : Fail([`\${key} needs to be an email`]))

// The validation super class we need
const Validation = run => ({
run,
concat: other => Validation((key, x) => run(key,x).concat(other.run(key.x)))
})

const validate = (spec, obj) => {
List.(Object.keys(spec)).foldMap(key => {
spec[key].run(obj[key])
}, Success.of(obj))
}

const validations = {name: isPresent, email: isPresent.concat(isEmail)}```

## Function Modelling

```// 
const { Either } = require('../types');

const toUpper = x => x.toUpperCase();
const exclaim = x => x.concat('!');

const Fn = run => ({
run,
map: f => Fn(x => f(run(x))),
concat: other => Fn(x => run(x).concat(other.run(x))),
});

const res = Fn(toUpper)
.concat(Fn(exclaim))
.run('fp sux');
console.log(res); // 'FP SUXfp sux!'

//  After adding in the capability to chain and promote to a Monad.
// Note: This is forming the basis of what is known as the Reader Monad.
const { Either } = require('../types');

const toUpper = x => x.toUpperCase();
const exclaim = x => x.concat('!');

const Fn = run => ({
run,
chain: f => Fn(x => f(run(x)).run(x)),
map: f => Fn(x => f(run(x))),
concat: other => Fn(x => run(x).concat(other.run(x))),
});

Fn.of = x => Fn(() => x);

const res = Fn(toUpper)
// This is called a Reader because we can transform
// and still get back to the original
.chain(upper => Fn(x => [upper, exclaim(upper)]))
.run('hi');
console.log(res); // ['HI', 'hi!']

const res = Fn('hello')
.map(toUpper)
.chain(upper => Fn(x => [upper, exclaim(upper)]))
.run('hi');
console.log(res); // ['HELLO', 'hi!']

//  Making the method more convenient - this becomes the Reader Monad!

const res = Fn(toUpper)
// This is called a Reader because we can transform
// and still get back to the original
.chain(upper => Fn(x => [upper, exclaim(upper)]))
.run('hi');
console.log(res); // ['HI', 'hi!']

const res = Fn('hello')
.map(toUpper)
.chain(upper => Fn.ask.map(config => [upper, config]))
.run({ port: 3000 });
console.log(res); // ['HELLO', {port: 3000}]```

The idea is that you can do dependency injection in here. You could pass in things like the db or strategy etc.

## The Endo Functor

What if we would rather (instead of combining functions by running both and combining the results) is create a composition as concatenation?

```const toUpper = x => x.toUpperCase();
const exclaim = x => x.concat('!');

const Endo = run => ({
run,
concat: other => Endo(x => run(other.run(x))),
});

// this is using the identity function again so
// we do not have to pass an arg to Endo.empty
Endo.empty = () => Endo(x => x);

List([(toUpper, exclaim)])
.foldMap(Endo, Endo.empty())
.run('hello');

console.log(res); // Hello!```

It's called `Endo` because it only works with `Endomorphisms` which means it can only go from type `a -> a` ie `String -> String`.

## Contramap

These are useful for if there is a bunch of functions that you want to combine. Contramaps allow us to pull out values during the execution.

```const Reducer = run => ({
run,
contramap: f => Reducer((acc, x) => run(acc, f(x))),
});

// Example
.contramap(pay => pay.user)
.run(state, { user: {}, currentPage: {} });```

Contramap is called a `Contravariant Functor`. If you have a `map` and `contramap` where you can change the input AND the output it is called a `Profunctor`.

## Function Modelling Equivalences

```const login = (state, payload) =>
: state;

const setPrefs = (state, payload) =>

// (acc, a) -> acc
// (a, acc) -> acc
// a -> (acc -> acc)
// a -> Endo(acc -> acc)

// Fn(a -> Endo(acc -> acc))
const Reducer = run => ({
run,
contramap: f => Reducer((acc, x) => run(acc, f(x))),
concat: (acc, x) => run(acc, f(x)),
});

// instead of this, we can use our knowledge of equivalences
// mentioned above to rewrite this

const state = { loggedIn: false, prefs: {} };
const payload = { email: 'admn', pass: 123, prefs: { bgColor: '#000' } };

// ... to this
: state;

const setPrefs = payload => Endo(state) =>

const state = { loggedIn: false, prefs: {} };
const payload = { email: 'admn', pass: 123, prefs: { bgColor: '#000' } };

// or this
: state;

const setPrefs = payload => state =>

Knowing these functional equivalences gives you the ability to model things based on what is available in the APIs as well as structuring your APIs.

## Composing Functors

For those familiar with `fold`, `extract` does not take a function and pass it to the function, it just takes it out.

The example given here is creating a function `TaskEither` by composition of functors `Task`, `Either`.

Here we get an issue that we cannot write a `chain` method.

Helps us around the chaining issue that came up from composing functors.

```const users = []; // pretend an array of users
const following = []; // pretend an array of objects of user following user
const find = (table, query) =>

const app = () =>
find(users, { id: 1 }) // Task(Either(User))
.chain(eu =>
eu.fold(Task.rejected, u => find(following, { follow_id: u.id })),
)
.chain(eu => eu.fold(Task.rejected, fo => find(users, { id: fo.user_id })))
.fork(console.err, eu => eu.fold(console.error, console.log));

app(); // returns User object ie {id: 2, name: 'Marc'}```

So we note this sucks, so we want to transform this into a `TaskEither` monad:

```const { TaskT, Task, Either } = require('../types');
const { Left, Right } = Either;

// This thing knows how to "chain" chain

const users = []; // pretend an array of users
const following = []; // pretend an array of objects of user following user
const find = (table, query) =>

const app = () =>
find(users, { id: 1 }) // Task(Either(User))
.chain(u => find(following, { follow_id: u.id }))
.chain(fo => find(users, { id: fo.user_id }))
.fork(console.err, eu => eu.fold(console.error, console.log));

app(); // returns User object ie {id: 2, name: 'Marc'}```

```const { FnT, TaskT, Task, Either, EitherT } = require('path/to/types');

// the challenges come from when instead of map we start to
// return eithers or functions or tasks within these things
// if we chain - see below
const res = App.of(2).map(x => x + 1);
console.log(res);

res.fold(console.error, fn =>
fn.run({ myEnv: true }).fork(console.error, console.log),
); // 3

// Chaining
const res = App.of(2)
.run({})
.fork(console.error, fi => fi.fold(console.error, console.log));```

You get these stacks of transformers and you have to get things in the right spot.

Brian here talks about how he does not love Monad transformers. Sometimes they're useful and they're around so it's good to know and can be useful if you keep it shallow.

Free Monads are usually not what you want. They solve a specific problem.

The free monad is a way to take your functions and treat them like data types.

```//  the base
const { liftF } = require('../lib/free');
const { Id } = require('../lib/types');

const httpGet = url => Task();
// we could hold a data type
const httpGet = url => HttpGet(url);
// doing so enables us to do things like...
// HttpGet(url).chain(contents => HttpPost('./analytics', contents));

//  an interpreter to interpret the new structure
const {taggedSum} = require('daggy')
const Http = taggedSum('Http', Get: ['url'], Post: ['url', 'body'])
console.log(Http.Get('/home')) // {url: '/home'}

// enables us to do thingsl like this.
// Get('/home').cata({
//   Get: url => 'get',
//   Post: (url, body) => 'post'
// })

// now we chan hange our httpGet
const httpGet = url => LiftF(Http.Get((url)));
const httpPost = (url, body) => LiftF(Http.Posts((url, body)));

const app = () => httpGet('/home').chain(contents => httpPost('/analytics'), contents)

const interpret = x => x.cata({
Get: url => Id(`contents for \${url}`),
Post: (url, body) => Id(`posted \${body} to \${url}`)
})

const res = app().foldMap(interpret, Id.of)
console.log(res.extract()) // posted contents for /home to /analytics```

Brian normally stubs Id.of in before Task so he can get an idea of what is going on.

The catamorphism is essentially being used as a bunch of ifs. JS doesn't give the tools out of the box, so that is what it is used for.

Free monads can be useful - Brian mentions one that he did for posted packages to Bower. It was a great solution to make sure you weren't accidentally posting to NPM everytime you used it.

## Lenses

You can do anything with lenses. You could rewrite every app in just lenses.

```const { toUpper, view, over, lensProp, compose } = require('ramda');

const L = {
name: lensProp('name'),
street: lensProp('street'),
};

const user = { address: { street: { name: 'Maple' } } };
const res = view(
compose(
L.street,
),
user,
); // allows us to compose
console.log(res); // { name: 'Maple'}

// allows us to set value
const res2 = over(
compose(
L.street,
L.name
),
toUpper
user,
); // allows us to compose
console.log(res); // { name: 'MAPLE'}```

Note: Lenses are also immutable.

If you had an `Either` of a property with everything inside a `Task`, we could jump deep inside of these properties, open things up, change it and then put it all back together.

It gets very powerful. It's like treating functors like properties.

Compose for lenses compose backwards and get from left to right.

## Building a CLI App

Brian goes through an overview of how he build a CLI app.

Things that he goes through is to apply things that we've learned with catamorphisms, Free Monads etc to enable a CLI blog post.

He also uses an example of an interpreter test that uses its own version of testing the identity (done using `dbToId` and `consoleToId`).

"The different between `Free` and `Fix` is that `Free` is a `Fix` with an endpoint to it."

## Creating a Redux Alternative

In this app, Brian uses lenses to overwrite and update state in the reducer.

Brian manages to remove the `state` from the function by using `ask` from the `Fn` type that Brian supplies to the course.

Brian eludes to the fact that TS doesn't love things like `Promise<Either<Task>>` as it is not built for that. There are some workarounds.