*Andy Hunt*

*(And can they be safe?)*

- Undefined
- Null
- Boolean
- String
- Number
- Object
- Symbol

*Wikipedia*

*Wikipedia*

```
const a = null;
a.prop; // #1
const b = undefined;
b.prop; // #2
```

What happens at 1 and 2?

- π₯ TypeError: Cannot read property 'prop' of null π₯
- Silently fails, returns undefined

```
> typeof null
'object'
```

- When the input is an array of > 0 items?
- When the input is an empty array?
- When the input is not an array?

Null, undefined or false?

```
const a = { a: { b: { c: [1, 2, 3] } } };
const b = { a: { b: { c: undefined } } };
const sumC = data => {
// what goes in here?
};
```

```
const a = { a: { b: { c: [1, 2, 3] } } };
const b = { a: { b: { c: undefined } } };
const add = (a, b) => a + b;
const sumC = data => data.a.b.c.reduce(add, 0);
sumC(a); // 6
sumC(b); // ?
```

TypeError: Cannot read property 'reduce' of null

```
const a = { a: { b: { c: [1, 2, 3] } } };
const b = { a: { b: { c: undefined } } };
const add = (a, b) => a + b;
const sumC = data => {
if (data.a.b.c && Array.isArray(data.a.b.c)) {
return data.a.b.c.reduce(add, 0);
}
// What do we return here?
}
```

```
// Option 1
return false;
```

```
// Option 2
return null;
```

```
// Option 3
throw new Error("An array is required to sum");
```

```
// Option 4
throw new CannotSumError("C should be an array");
```

*Crocks*

data Bool = True | False

*User defined types*

type EventId = Int

*Type aliases / Synonyms*

add :: Int -> Int -> Int

*Function signatures*

data Maybe a = Just a | Nothing

Maybe is well suited for capturing disjunction when the cause of the "error" case does not need to be communicated. For example, providing default values on specific conditions.

```
const a = { a: { b: { c: [1, 2, 3] } } };
const b = { a: { b: { c: undefined } } };
const add = (a, b) => a + b;
const sumC = data => {
if (data.a.b.c && Array.isArray(data.a.b.c)) {
return Just(data.a.b.c.reduce(add, 0));
}
return Nothing();
}
```

```
const prop = require("crocks/Maybe/prop");
const propPath = require("crocks/Maybe/propPath");
const data = { a: { b: { c: [1, 1, 2, 3, 5] } } };
const a = prop("a", data); // Just { b: { c: [1, 1, 2, 3, 5] } }
const b = prop("b", data); // Nothing
const c = propPath(["a", "b", "c"], data); // Just [1, 1, 2, 3, 5]
const d = propPath(["a", "b", "d"], data); // Nothing
```

A value which has a functor must provide a map method. The map method takes one argument

`map :: Functor f => f a ~> (a -> b) -> f b`

```
Just.prototype.map = function(fn) { return Just(fn(this.value)) };
```

`Nothing.prototype.map = function(fn) { return this; };`

```
const a = { a: { b: { c: [1, 2, 3] } } };
const b = { a: { b: { c: undefined } } };
const sumC = data =>
propPath(["a", "b", "c"], data)
.map(vals => vals.reduce(add, 0));
sumC(a); // Just 6
sumC(b); // Nothing
```

`propPath :: Foldable f => f (String | Integer) -> a -> Maybe b`

Arrows indicate currying

Value is only returned when all other arguments are provided

"f" has to be an ADT which implements the foldable typeclass (i.e. an array or List)

```
propPath :: Foldable f => f (String | Integer) -> a -> Maybe b
map :: (a -> b) -> m a -> m b
reduce :: (b -> a -> b) -> b -> m a -> b
compose :: ((y -> z), ..., (a -> b)) -> a -> z
pipe :: ((a -> b), ..., (y -> z)) -> a -> z
```

```
// getC :: a -> Maybe b
const getC = propPath(["a", "b", "c"]);
// sum :: Foldable f => f Number -> Number
const sum = reduce(add, 0);
// sumC :: a -> Maybe Number
const sumC = pipe(getC, map(sum));
```

`const sum = reduce(add, 0);`

"empty" value (aka identity)

Combines two values together (aka concat)

any ADT that provides both an empty and a concat function can be used as a Monoid

Each Monoid provides a means to represent a binary operation and is usually locked down to a specific type. These are great when you need to combine a list of values down to one value.

```
// Instead of this
const add = (a, b) => a + b;
const sum1 = reduce(add, 0);
// We can use the built in behaviours of the Sum Monoid
const sum2 = mreduce(Sum);
```

π‘Note that sum1 and sum2 are equivalent - both take an array of numbers and return a number

```
// sumC :: a -> Maybe Number
const sumC = pipe(
propPath(["a", "b", "c"]),
map(mreduce(Sum));
```

Our program has been completely built from generic, reusable library code

`mreduce`

vs `mconcat`

vs `mreduceMap`

vs `mconcatMap`

```
mconcat :: Monoid m, Foldable f => m -> f a -> m a
mconcatMap :: Monoid m, Foldable f => m -> (b -> a) -> f b -> m a
mreduce :: Monoid m, Foldable f => m -> f a -> a
mreduceMap :: Monoid m, Foldable f => m -> (b -> a) -> f b -> a
```

`mreduce`

vs `mconcat`

vs `mreduceMap`

vs `mconcatMap`

*Jumping back...*

```
// head :: Foldable f => f a -> Maybe a
const head = xs => (Array.isArray(xs) && xs.length > 0 ? Just(xs[0]) : Nothing();)
```

```
// head :: Foldable f => f a -> Maybe a
function head(xs) {
if (Array.isArray(xs) && xs.length > 0) {
return Just(xs[0]);
}
return Nothing();
}
```

`Nothing`

?
`Maybe`

is just the start of this adventure...
data Either e a = Left e | Right a

data Result e a = Err e | Ok a

data Async e a = Rejected e | Resolved a

data RemoteData e a = NotAsked | Loading | Error e | Success a

type Pair a b = (a, b)

The specifications in this list do not derive from goals such as trying to write rules for lists and maps. Instead, they start by

noticingrules that apply in common to disparate structures.

Yeah this is really not happening. It totally ignores reality in favor of typed-languagefantasy land, making a more awkward and less useful API just to satisfy some peoples' aesthetic preferences that aren't even applicable to JavaScript.