If you want to see how sloppy your thinking is, try writing. If you want to see how sloppy your writing is, try writing math.

–Someone said this

“Monad” is a well-defined mathematical object that must satisfy axioms known as the monad laws: Left Identity,
Right Identity, and Associativity. One way to implement a monad is to define the functions `return`

and `bind`

such
that they obey the monad laws. (And once you have that, you can derive other functions, as well.)

`return :: a -> m a`

is the “unit” operation for the monad `m`

. Essentially, `return`

takes any value and puts it
into the monadic context. The candidate for an analogous function on the `Promise`

API is `resolve`

. However,
because of the OO nature of JavaScript we can’t use `Promise.resolve`

as a pure function.
I cannot simply write `.then(Promise.resolve)`

– that gives me this delightful error: “Receiver of Promise.resolve
call is not a non-null object”. So to be fair, we can use the lambda `x => Promise.resolve(x)`

as our `return`

.

`bind :: m a -> (a -> m b) -> m b`

enables you to compose, flattening as you go. The analogous `Promise`

function for
`bind`

is `then`

.

Note that in the examples below, the `≡`

symbol in an expression like `a ≡ b`

indicates that you can confidently
replace one side of `≡`

with the other side, and your program will behave the same way.

The question is: Does `Promise`

satisfy the monad laws?

```
Promise.resolve(a).then(f) ≡ f(a)
```

Left Identity appears to hold as long as the function `f`

that takes an `a`

and returns a `Promise`

(i.e. `a -> Promise b`

).
But not quite. What if the type `a`

is itself a `Promise`

? Suppose `f`

is

```
const f = p => p.then(n => n * 2)
```

In this example `f`

is a function from `Promise Number -> Promise Number`

. Let’s plug in a `Promise Number`

for `a`

to match up
with the expected input for `f`

. Then we can evaluate the expression:

```
const a = Promise.resolve(1)
const output = Promise.resolve(a).then(f)
// output :: RejectedPromise TypeError: p.then is not a function
```

The value that gets passed to `f`

is implicitly unwrapped. It is a `TypeError`

to pass a function to `then`

that takes a `Promise`

for an argument. Note that we can evaluate the right-hand side of the equivalence to get a different result:

```
const output = f(a)
// output :: ResolvedPromise 2
```

Therefore, Left Identity does not hold for *every* function of the form `a -> Promise b`

: It only holds if `a`

is
not itself a `Promise`

.

```
p.then(x => Promise.resolve(x)) ≡ p
```

This holds (where `p`

is some `Promise`

).

```
p.then(f).then(g) ≡ p.then(x => f(x).then(g))
```

As with Left Identity above, Associativity is only satisifed if `f`

and `g`

play nice. If `f`

or `g`

take a `Promise`

argument, then, for the same reason as shown above, this law will not hold.

Failing to satisfy one law would have been sufficient to disqualify `Promise`

from being a monad. The examples
above show that `Promise`

satisfies only one out of three: Right Identity.

Laws matter. They can give you confidence about the properties of the code you write, and how you can rewrite it. They permit you to port concepts across languages – to the extent the language can support them. On the other hand, if you are using JavaScript, then lawfulness may not be a priority.

10 April 2018