# Starting Functional JavaScript

(HJKL Arrow Keys to Navigate)

## Pure Functions

Functions that have no *side effects* are said to be pure.

*Which of these functions is pure?*

`const add = (x, y) => x + y`

`const trace = (tag, x) => console.log(tag, x) ?? x`

`const getTime = () => Date.now()`

```
const resolveUser = ({ token }, models) =>
models.user.isValidToken(token)
? () => models.user.fetch(token)
: async () => null
```

Pure functions are *useless*, *easily tested*
, and *referentially transparent*.

```
const add = (x, y) => x + y
add(2, 3) === 5;
source.replace('add(2, 3)', '5');
```

## Currying

and

### Partial Application

## Curried Functions

Take their arguments one at a time.

`const add = x => y => x + y`

```
function add(x) {
return function addToX(y) {
return x + y;
}
}
```

## Partial Application

Use closure to defer computation.

`const add2 = add(2)`

```
add2(3) === 5
add2(4) === 6
```

Partial application has many uses e.g. generic functions or fluent computations.

## Function Composition

Combines many functions into one by applying each function to the result of the previous one. In other words, makes one function from two (or more) others.

```
// binary compose
const compose =
(f, g) =>
x => f(g(x))
const addTwice2 = compose(add(2), add(2))
const deepSerialClone = compose(JSON.parse, JSON.stringify)
const isAdmin = compose(
x => x === 'admin',
({ role }) => role
)
```

## Use Case: Class Mixins

JavaScript class mixins are a way to share behaviour among classes

```
const DraggableMixin = superclass => class extends superclass {
onDragstart(event) { /* ... */ }
onDrop(event) { /* ... */ }
}
```

```
@customElement('draggable-image')
class DraggableImage extends DraggableMixin(LitElement) {
@property({ type: String, reflect: true }) src = '';
@property({ type: String, reflect: true }) alt = '';
render() { return html`<img src="${this.src}" alt="${this.alt}">` }
}
```

## Pointfree Style

Functions which reference their own data are said to be "pointed".
Likewise, functions which do not reference their parameters
are said to be "pointfree".
With curried and point-free functions, always take your
*data* as the *last* parameter.

```
const map = f => xs => xs.map(f)
const filter = p => xs => xs.filter(p)
const assign = a => o => ({ ...o, ...a })
const handleAsJson = resp => resp.json()
fetch('/users')
.then(handleAsJson)
.then(filter(isAdmin))
.then(map(assign({admin: true}))
```

## Functors

A functor is a container for some value, like an envelope. Functors can map
from some value `x`

in a category to another value `y`

in that same category.
`Array`

and `Promise`

are both functors.

```
const inc = x => x + 1
[1].map(inc) // [2]
Promise.resolve(2)
.then(inc) // Promise 3
```

## Crocks

## Crocks Helpers

```
import propOr from 'crocks/helpers/propOr'
import propPathOr from 'crocks/helpers/propPathOr'
// propOr :: A -> String -> {[String]: A} -> A
propOr(null, 'name', { name: 'ftr' }) // 'ftr'
propOr(null, 'name', { date: '2019' }) // null
// helpers are curried by default
const getName = propOr(null, 'name')
getName({ name: 'Forter' }) // 'Forter'
const getFirstCourseId = propPathOr(null, ['courses', '0', 'id'])
getFirstCourseId({ courses: [{ id: 1 }] }) // 1
getFirstCourseId({ courses: 'blammo!' }) // null
```

## Crocks Logic

```
import { propOr, compose, isTruthy, not, and, or } from 'crocks'
const isUser = compose(isTruthy, propOr(null, 'token'))
const isRich = compose(x => x > 1000, propOr(0, 'balance'))
const hasFriends = compose(x => x.length, propOr([], 'friends'))
const isFriendly = and(isUser, hasFriends)
const isUnfriendly = not(isFriendly)
const shouldFriend = or(isFriendly, isRich)
```

## Crocks Curry

Crocks' curry is very flexible.

```
import curry from 'crocks/helpers/curry'
const wellCurried = curry(
(x, y) => z => (foo, bar) => 'baz'
)
wellCurried(1) // curry((y, z, foo, bar) => 'baz')
wellCurried(1, 2, 3) // curry((foo, bar) => 'baz')
```

## Monoids

A monoid is a type which has an 'empty' value, and an operation to combine values. Combining a value with the 'empty' value always produces the same value.

- What is the empty value for numbers under addition?
- Under multiplication?

## You're already using monoids!

`&&`

forms a monoid with`true`

as empty value`||`

forms a monoid with`false`

as empty value`String#concat`

forms a monoid with`''`

as empty value.`Object.assign`

forms a monoid with`{}`

as empty value`Array#concat`

forms a monoid with`[]`

as empty value

`mreduceMap`

Folds an array under a monoid of your choice, first mapping your monoid constructor over it.

```
import { All, Any } from 'crocks'
import { compose, mreduceMap } from 'crocks/helpers'
import isNil from 'crocks/predicates/isNil'
import not from 'crocks/logic/not'
const hasToken = compose(not(isNil), propOr(null, 'token'))
const isFraud = compose(greaterThan(0.5), propOr(0, 'score'))
const allAreUsers = mreduceMap(All, hasToken)
const anyAreFraud = mreduceMap(Any, isFraud)
```

## Monad

Like a functor, Monads can map over their contents.
Monads have the added ability to unwrap their self-similar
contents. This power is called `chain`

, `bind`

, or `flatMap`

```
[1]
.map(x => [x + 1]) // [ [ 2 ] ]
[1]
.flatMap(x => [x + 1]) // [2]
```

## Maybe Monad

The Maybe monad wraps a value which may not exist. It has two instances: `Just a`

and `Nothing`

. Mapping over a `Just`

works as expected. Mapping over a
`Nothing`

skips execution.

```
import { ifElse, isNumber, Just, Nothing, chain } from 'crocks'
const safe = p => ifElse(p, Just, Nothing)
const gt10 = x => x > 10
const safeNumber = safe(isNumber)
const maybeBig = safe(gt10)
const bigNumber = compose(
chain(maybeBig),
safeNumber
)
```

## Maybe Monad - Binary

```
import { Maybe, safe, isNumber } from 'crocks'
const safeNumber = safe(isNumber)
const safeAdd = (x, y) => {
const maybeX = safeNumber(x)
const maybeY = safeNumber(y)
return maybeX.chain(
x_ => maybeY.map(y_ => x_ + y_)
)
}
safeAdd(1, 2) // Maybe 3
safeAdd(1, null) // Nothing
safeAdd('רק', 'ביבי') // Nothing
```

## Maybe Monad - Binary

Wait!! People code like that?

**👉 NOPE 👈**

Monads are also applicatives, which means we can lift any function into
'monadic space' with `lift`

```
import { liftA2 } from 'crocks';
const add = (x, y) => x + y;
const safeAdd = (x, y) =>
liftA2(add, safeNumber(x), safeNumber(y))
```

Thanks For

Watching!