## Category Theory for Promises/A+

Promises are
being debated
in the JavaScript community. The most popular specification is
Promises/A+. It’s a
fairly small specification, containing only a single function: `then`

.

The function is heavily overloaded which makes it quite complicated - way more than it has to be. I’ll try to show how category theory can give us a much simpler, more generalised and lawful API!

A proper Promise/A+ implementation must provide a `then`

method which
always returns a promise. The `then`

method takes two arguments:

```
Promise.prototype.then = function(onFulfilled, onRejected) {
// ...
};
```

The `onFulfilled`

and `onRejected`

callbacks can return a promise or
some other value. Both of the callbacks are optional - so let’s only
focus on the `onFulfilled`

callback for now. If we tried to extract
some type signatures it would like something like so:

```
// then :: Promise a -> (a -> Promise b) -> Promise b
// then :: Promise a -> (a -> b) -> Promise b
```

Where the top signature is tested for and the bottom is a fallback. Functional programmers might notice those two type-signatures. They come up all the time in Scala and Haskell:

```
// flatMap :: m a -> (a -> m b) -> m b
// map :: m a -> (a -> b) -> m b
```

So `then`

is an overloaded `flatMap`

, which falls back to `map`

if the
function passed in doesn’t return a promise. Now time for some
category theory.

### Category Theory

The `flatMap`

function is part of being a Monad. The other part is a
function with multiple names:

- point
- pure
- return

They all mean the same thing, taking a value and putting it into the monadic context. Putting it together, here’s the monad class:

```
class Monad m where
flatMap :: m a -> (a -> m b) -> m b
point :: a -> m a
```

So does Promises/A+ define a monad? All we’d need is a way to take a value and put it inside of a (fulfilled) promise. Sadly, the spec states:

As with Promises/A, this proposal does not deal with how to create, fulfill, or reject promises.

But what’s interesting is that the proposal defines what is a promise:

“promise” is an object or function with a then method whose behavior conforms to this specification.

The specification doesn’t define a way of creating a promise - but it
*does* define what a promise looks like. That means we can define our
own `point`

function which should hopefully work with other promise libraries:

```
function point(a) {
return {
value: a,
then: function(onFulfilled) {
var promise = this;
setTimeout(function() { promise.value = onFulfilled(promise.value).value; }, 0);
return promise;
}
};
}
```

(**Update:** original `point`

implementation was completely wrong. I
*think* the above conforms to part of the spec. It’d need some more
details to work when passed to other libraries)

Let’s also make a function for treating `then`

like `flatMap`

(i.e. no
second argument):

```
function flatMap(p, f) {
return p.then(f);
}
```

So, we’ve made a promise monad. What does that mean? Before I explain
why that’s useful, let me talk about the `map`

function above.

If the function we give to `then`

as `onFulfilled`

*doesn’t* return a
promise, then it creates a new promise after applying the function. If
it didn’t have the special case for promises, then it’d be functor:

```
class Functor f where
map :: f a -> (a -> b) -> f b
```

What’s impressive is that we can *derive* a functor using just the
`point`

and `flatMap`

that we defined above!

```
function map(p, f) {
return flatMap(p, function(a) {
return point(f(a));
});
}
```

The trick is that `point`

will even make a promise out of a promise!

So monads are useful for defining functors, what else are they good for? Let’s imagine a promise library gave us a nested promise (a promise within a promise). We can write a function to flatten it:

```
function identity(a) {
return a;
}
function join(p) {
return flatMap(p, identity);
}
```

The above will work for *any monad*. List of lists? Optional optional
value? If the JavaScript community settled on using `flatMap`

as a
method, we could write DRY, generalised code for monads.

Above I showed how we can get a functor from any monad. We can do one
better; all monads form *applicative* functors:

```
class (Functor f) => Applicative f where
point :: a -> m a
ap :: m a -> m (a -> b) -> m b
```

Here’s how to derive the `ap`

function:

```
function ap(p, pf) {
return flatMap(pf, function(f) {
return map(p, f);
});
}
```

Applicatives have some really useful functions:

```
// liftA2 :: f a -> f b -> (a -> b -> c) -> f c
function liftA2(pa, pb, f) {
return ap(pb, map(pa, function(a) {
return function(b) {
return f(a, b);
};
}));
}
```

This is very useful for promises. It allows use to run multiple promises and run a function when they’re all finished:

```
liftA2(readFile('hello.txt'), readFile('world.txt'), function(hello, world) {
console.log(hello + ' ' + world);
});
```

Lots of promises libraries write special functions to achieve the above magic. But again, we can be more DRY because this stuff works for all applicatives!

We could even combine the above with operator overloading for a nice DSL.

### Recommendations

We’ve only been focusing on the `onFulfilled`

case - we left out the
`onRejected`

case. What should we do with that?

I think that should just be an additional method on promises - not on
an overloaded `flatMap`

:

```
Promise.prototype.onRejected = function(callback) {
// ...
};
```

(Scala provides an `onFailure`

method
to do the same thing)

It seems like the JavaScript community has settled on `then`

as being
the name for `flatMap`

(that’s fine, in Haskell it’s called `bind`

or
`>>=`

). I think `then`

should only take the `onFulfilled`

function and
it should have *unspecified* behaviour if the function doesn’t return a
promise (for simplicity; map can be derived).

I also think the specification should define a way of creating promises. It’s only a few lines to create a compatible promise but I don’t think that should be up to the library’s users.

And lastly, it would be nice to have a `done`

method which forked the
promise. That would allow the API to be *purely* functional. No
effects would happen until `done`

was called. Turning side-effects
into an effect. Sadly, I think the JavaScript community would not
appreciate this approach.

So we should have something which looks like this:

```
Promise.point = function(a) {
// ...
};
Promise.prototype.then = function(onFulfilled) {
// ...
};
Promise.prototype.onRejected = function(callback) {
// ...
};
// Possibly
Promise.prototype.done = function() {
// ...
};
```

Just having the two functions of the monad interface allows us to
*derive* functions to map over the promise, flatten a promise, run a
function when promises are finished and much more. These functions
will also work with other monads or applicative functors if we rely on
`point`

and `then`

as an API for different structures.

### Summary

Recognising that promises are monadic gives us an API which allows us to derive lots of useful functions. These functions are based off of category theory which also means that they work with not just promises - allowing the API to be consistent and DRY for many structures.

I think we should apply that knowledge directly to a promises
specification. An implementation would only require three *very*
simple functions:

- point(a)
- then(f)
- onRejected(f)

No surprising overloaded behaviour or optional arguments. It would be compatible with some existing libraries.

I believe that the JavaScript community needs to act quickly to achieve a more consistent and simple API before promises become solidified. The time is now!