• Monads For JavaScript Developers
  • Author: MelkorNemesis
  • The Nuggets translation Project
  • Permanent link to this article: github.com/xitu/gold-m…
  • Translator: zenblo
  • Proofread: PassionPenguin, ZavierTang

Monads for JavaScript developers

As much as any programmer, I want to know what Monads are. However, whenever I search Monads online, I only find a large number of articles on the theoretical category of Monads, and other resources seem to be of little reference value.

I spent a lot of time and energy trying to figure out what a Monads was. I started learning Haskell, but after a few months of learning Haskell, I suddenly realized that everyone was making a big deal out of Monads. If you’re a JavaScript developer, you probably use it every day, and you just don’t realize it.


This article won’t go into too much detail about the theoretical scope of Monads or Haskell, but there is one thing we should always know — when searching for Monads on the Internet, we should not miss this definition:

(>>=) :: m a -> (a -> m b) -> m b
Copy the code

This is the definition of the bind operator in Haskell. Different languages have different names for this operation, but the meaning is the same. For example, some alternative names are chain, bind, flatMap, then, andThen.

Monadic context

(> > =) : : m a - > (a - b) > m - > m: m b: monadic context. A, b: : context value (string, number,..)Copy the code

A Monadic Context is just a box that implements all the functions needed to make that box a Monad. A very simple (non-Monadic) box might look like this:

const Box = val= > ({ val }); 
const foo = Box("John");
Copy the code

This is a box wrapped only with values, and the box has no function because it has no method to implement it.

To make something a Monad, you have to make it behave like a Monad.

Then let’s go back to (>>=) :: m a -> (a -> m b) -> m b. M (> > =) a > > = (a – b) > m infix operators, and (> > =) operation is the result of the m b.

Existing problems

Did you notice that we have m a, but the function takes a? That’s what Monads is all about.

The (>>=) operation takes a value from the Monadic context Ma to expand it, so we only get a, which we pass to the function (a -> MB). It’s not surprising that you have to create your own code of conduct, which we’ll talk about later.

JavaScript 的 Promises

Promises in JavaScript are like Monads. More specifically, Promises have monad-ish behavior. To be Monad, it must also implement a Functor and Applicative. I mention this just for completeness, but we’re not going to get into any of this.

JavaScript Promises uses the.then() method to implement the Monadic interface. Let’s look at the following example:

// p :: m a :: Promise { 42 }
const p = Promise.resolve(42);
Copy the code

This typically creates a box with a value of 42 in the Promise. ☝️ This is our MAa.

Then we have a function that divides the number by two. The input is not wrapped in a Promise, but the return function is wrapped in a Promise.

// divideByTwo :: (a -> m b)
const divideByTwo = val= > Promise.resolve(val / 2);
Copy the code

☝️ this is our (a -> MB).

Again, notice that we have a value of 42 in the Promise, but the function divideByTwo accepts an unwrapped value, and we can still link these.

// p :: m a :: Promise { 42 }
const p = Promise.resolve(42);
// p2 :: m a :: Promise { 21 }
const p2 = p.then(divideByTwo);
// p3 :: m a :: Promise {10.5}
const p3 = p2.then(divideByTwo);
Copy the code

Or more obviously:

// p :: m a :: Promise {10.5}
const p4 = p.then(divideByTwo).then(divideByTwo);
Copy the code

This is the most important feature of Monads.

There’s a value in the box — Promise {42}, and you have a function that takes the expanded value 42. A does not match the type of a, and you can still apply this function to encapsulated values.

How is that possible?

This is because promises implement the THEN method and work that way. Most of the time, the code that runs in promises is asynchronous. But Promise’s single-handedness allows it to link a series of functions.

Monads abstracts out auxiliary data management, control flow, or side-effects of functions, transforming potentially complex sequences of functions into concise pipelines.

Custom Monad-style classes

I’ve compiled a very simple Monad-style class example in TypeScript that has no function side effects and allows linking functions.

class Dummy<T> {
  constructor(private val: T) {}

  chain<TResult>(fn: (value: T) = > Dummy<TResult>): Dummy<TResult> {
    return fn(this.val);
  }

  static unit<T>(val: T): Dummy<T> {
    return newDummy(val); }}const d = new Dummy(41);
d.chain(val= > new Dummy(val + 1))
 .chain(val= > new Dummy("The answer is: " + val));
Copy the code

Rules of Monad

Classes with Monad features must follow some rules.

  • The left unit
  • The right unit
  • Can be combined with sexual

You can find more information on the Internet. Put some code here to prove that the Dummy class follows these rules.

const m = Dummy.unit(1);
const f = (val: number) = > new Dummy(val + 1);
const g = (val: number) = > new Dummy(val + 2);

// 1
Dummy.unit(1).chain(f) ==== f(1)

// 2
m.chain(Dummy.unit) ==== m

// 3. Combinability
const m1 = Dummy.unit(1);
m.chain(f).chain(g) ==== m.chain(val= > f(val).chain(g)
Copy the code

== or === doesn’t work here, because object references are different. For this, I use the non-existent ====, but can be understood as the internal value of an object of a Monad-like class.

This paper summarizes

I hope this article has introduced you to Monads, and if you are a JavaScript developer, you use them every day. For example, provide the boxed value in the Promise to a function that needs the unwrapped value and return the new value wrapped in the Promise again.

The resources

  • En.wikipedia.org/wiki/Monad_…

If you find any mistakes in your translation or other areas that need to be improved, you are welcome to the Nuggets Translation Program to revise and PR your translation, and you can also get the corresponding reward points. The permanent link to this article at the beginning of this article is the MarkDown link to this article on GitHub.


The Nuggets Translation Project is a community that translates quality Internet technical articles from English sharing articles on nuggets. The content covers Android, iOS, front-end, back-end, blockchain, products, design, artificial intelligence and other fields. If you want to see more high-quality translation, please continue to pay attention to the Translation plan of Digging Gold, the official Weibo, Zhihu column.