liveBook · Manning

Monad

As explained in The Joy of JavaScript

An abstraction for sequencing computations through a context that can carry values and effects while supporting composition via flatMap-like chaining.

A monad lets functions that return wrapped values compose without accumulating wrappers. If a function returns an Id, ordinary map can leave an Id inside an Id. flatMap applies the function to the contained value and keeps the result in a single composable context. A monad also implements the functor map contract. section 5.4.2

Chain wrapped computations

If square and times3 each return an Id, `Id.of(2).flatMap(square).flatMap(times3).get()` produces `12`. The chain passes each result onward without requiring the caller to unwrap and rewrap between steps. For JavaScript arrays, flatMap likewise handles mapping and flattening together. section 5.4.2

Three equivalences make flatMap chains predictable:

  • Left identity: `M.of(a).flatMap(f)` is equivalent to `f(a)`. section 5.4.2
  • Right identity: `m.flatMap(M.of)` is equivalent to `m`. section 5.4.2
  • Associativity: `m.flatMap(f).flatMap(g)` is equivalent to `m.flatMap(a => f(a).flatMap(g))`. section 5.4.2
Listing 5.21 Block validation with flatMap
class Block {
   ...
 
   isValid() {
      const {
         index: previousBlockIndex,  
         timestamp: previousBlockTimestamp
       } = this.#blockchain.lookUp(this.previousHash);
      
       return Validation.of(this)
         .flatMap(checkTimestamps(previousBlockTimestamp))    #1
         .flatMap(checkIndex(previousBlockIndex))             #1
         .flatMap(checkTampering);                            #1
   }
}

Block validation uses the context to control the chain: Success runs the next Validation-returning check; Failure retains its error and skips the remaining checks. The result is a Validation value, not a Boolean. section 5.5.5 section 5.5.7

Use compose for functions returning unwrapped values and composeM for functions returning monads; composeM sequences them through flatMap. The same approach can validate a blockchain, its blocks, and their transactions by reducing over their validation results. That array-building traversal is not presented as scalable to billions of objects. section 5.5.6 section 5.5.7

Promise.then offers a useful resemblance: it accepts callbacks returning either plain values or promises and flattens the latter. Promises are not, however, claimed to satisfy the full Fantasy Land monad specification. section 8.2.2

How The Joy of JavaScript covers it

How deep it goes
Defines the map and flatMap contracts, demonstrates three laws, and builds chaining and composeM; defers extensive algebraic theory.
Examples
Works through Id and array chains, block-validation checks, blockchain traversal, and Promise.then flattening.
What it assumes
Assumes familiarity with JavaScript functions and map while teaching the monad contract without requiring category theory.
What you can do after
Build it from scratch with JavaScript mixins and composeM to chain Validation-returning checks.
How it connects
Connects functors, algebraic data types, function composition, Validation, and promises through mapping and wrapped-value chaining.

Also explained in

Compare how 6 books explain monad →

Related concepts

This explainer was generated by Manning's knowledge graph from the text of The Joy of JavaScript. The section links point to the parts of the book it draws on.