Monads and You

How to think about Promises

It's All About the Wrappers


            const arrayOfNumbers: Array<number> = [1, 2, 3];
            const setOfStrings: Set<string> = new Set(
              "one",
              "two",
              "three"
            );
          

Case Study: Array


            const x = 2;  // Initialized value
            const a = Array.of(x);  // Wrap
            const b = a.map((v) => v * 2)  // Map
            const y = b[0]  // Flatten
          

Generalizing


              class Identity<Value> {
                private constructor(private value: Value)
                static of(value: Value) {
                  return new Identity(value);
                }
                map(f: (v: Value) => Value) {
                  return new Identity(f(this.value));
                }
                flatten() {
                  return this.value;
                }
                flatMap(f: (v: Value) => Identity<Value>) {
                  return f(this.value);
                }
              }
            

              const x = 2;  // Initialize value
              const i = Identity.of(x);  // Wrap
              const j = i.map((v) => v * 2);  // Map
              const y = j.flatten();  // Flatten
              const k = j.flatMap((v) => Identity.of(v * 2));  // Flatten then map
            

Shane, you literally haven't mentioned Promises yet.

Very astute.

Promises are just like Arrays

But, you know, with more confusing semantics


            const x = 2;  // Initialize value
            const p = Promise.resolve(x);  // Wrap
            const q = p.then((v) => v * 2)  // Map
            const y = await q;  // Flatten
            const z = q.then((v) => Promise.resolve(v * 2))  // flatmap?
          

Async shmasync

async is just Promise.resolve()


            async function lift<Value>(x: Value) {
              return x;
            }

            const p = lift(2);  // Wrap

            function lift<Value>(x: Value) {
              return Promise.resolve(x);
            }

            const p = lift(2);  // Wrap
          

So a Monad is...?

Ah, right. Let's start with Functors.

Bear with me.

Functor

  • Has a map method (e.g. Array.map() or Promise.then())

Monad

A functor, plus...

  • Has a wrap method (e.g. Array.of() or Promise.resolve())
  • Has a flatMap/bind/chain method (e.g. Identity.flatMap() or Promise.resolve())

So, are Promises Monads?

Well... no. There aren't any proper monads built in to Javascript.

But hopefully it's still a useful way to think about it!