liveBook · Manning

Flatmap

As explained in The Joy of JavaScript

Functional composition operations that transform values and flatten nested computations or containers.

flatMap combines a transformation with a flattening step. On a JavaScript array, it is the common `map`-then-`flat` sequence in one operation: a callback produces values, and the result does not retain the extra array layer created by mapping. Like `flat`, it returns a new array rather than changing the original. section 5.2.2 section 5.2

Replace a nested intermediate array

When each block contains an array of transactions, `.map(prop('data')).flat()` first creates an array of transaction arrays. `.flatMap(prop('data'))` expresses the same step directly, leaving one array of transactions for the later balance calculation. section 4.7

Listing 4.16 computeBalance using map, filter, and reduce
function computeBalance(address, ledger) {
   return Array.from(ledger) 
    .filter(not(prop('isGenesis'))) 
    .flatMap(prop('data'))                #1
    .map(balanceOf(address)) 
    .reduce(Money.sum, Money.zero()) 
    .round();
}

The balance pipeline filters blocks, flat-maps their transaction data, converts transactions to monetary effects, and reduces those effects to a total. section 4.7

The idea extends beyond arrays. Mapping a function that returns a container can produce a container inside another container. A monad supplies `flatMap` to compose such functions without retaining that extra wrapping. For a simple `Id` container, the shown implementation uses `this.map(f).get()`; `chain` and `bind` are alternative names. This is contextual composition: the container participates in how successive functions connect. section 5.4.2 section 5.2.2

Choose the form that matches the work:

  • Use array `flatMap` when a mapping step would otherwise be followed by `flat`; it also avoids the separate intermediate result of those two calls. section 4.7 section 5.4.2
  • Use a container’s `flatMap` when each function returns another instance of that container and the computations must remain chainable. section 5.4.2

With `Validation`, the context is success or failure. A successful result can continue through `flatMap`; a failure skips subsequent checks and propagates its error. This keeps validation in the chain instead of interleaving each operation with `if/else` or `try/catch`. Paired with `reduce`, `flatMap` can also collapse validation across a nested structure to one result. section 5.5.3 section 5.5.7

Listing 5.23 HasValidation mixin
const HasValidation = () => ({
    validate() {   
       return [...this]                                             #1
        .reduce((validationResult, nextItem) =>                     #2
             validationResult.flatMap(() => nextItem.validate()),
          this.isValid()                                            #3
         );
    }
});

The reducer starts with an object’s validation result and flat-maps each subsequent item’s validation into that result. section 5.5.7

How The Joy of JavaScript covers it

How deep it goes
Explains map-then-flat, implements a simple container protocol, and illustrates monad laws with arrays.
Examples
Shows blockchain balance calculation, array-based monad laws, and validation of nested blockchain objects.
What it assumes
Assumes familiarity with map and basic functional composition; defers the details of object iteration.
What you can do after
Build it from scratch for a simple container, or apply it to flatten array pipelines and compose validation results.
How it connects
Connects flatMap to map, flat, function composition, monads, reduce, and Validation.

Also explained in

Compare how 5 books explain flatmap →

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.