Fun Fun Function
Standard map operations fail when callbacks return data containers, requiring monads to unwrap nested structures through flatMap or promise chaining.
AI-assisted summary of Monad - FunFunFunction #21 — original source. Check the original for full context.
Source published:
Key ideas
- A monad is fundamentally a more powerful functor that implements flatMap (or equivalent methods like bind, chain, or then) in addition to map. (0:00)
- Using standard map on functions returning container structures like streams causes nested wrapping (Stream<Stream<Value>>), whereas flatMap flattens and unwraps the inner value. (5:07)
- JavaScript Promises act as monads through .then(), which automatically unwraps nested promises returned within its callback. (8:10)
Detailed notes
## Background Published by the YouTube channel Fun Fun Function on February 29, 2016, this video tackles the concept of monads in JavaScript. Host MPJ explains that while a functor is an object implementing `map`, a monad is a more powerful functor that also implements `flatMap` to eliminate nested containers.
## TL;DR In this episode, MPJ cuts through academic category theory and Haskell jargon to deliver an intuitive, practical explanation of monads for everyday developers. Using reactive event streams with Bacon.js and the Google Translate API, he demonstrates how applying `.map()` to an asynchronous operation results in awkward nested streams. By replacing `.map()` with `.flatMap()`, the inner stream is automatically unwrapped, revealing the bare value. He concludes by explaining how common tools like JavaScript Promises use `.then()` as a monad flattening mechanism under an alternate name, alongside Haskell's `bind` and Fantasy Land's `chain`.
## Atmosphere & style The video maintains an energetic, pragmatic, and approachable tone typical of MPJ's 'Failing Together' ethos. Rather than intimidating viewers with rigid mathematical formalism, MPJ adopts an empathetic, conversational delivery filled with lighthearted self-deprecation and expressive reactions when code fails. It feels like pairing with an enthusiastic senior colleague who deliberately demystifies complex functional programming concepts through live coding and relatable real-world examples.
## Bulletin - [00:00](https://www.youtube.com/watch?v=9QveBbn7t_c&t=0s) A monad is fundamentally a more powerful functor that implements flatMap (or equivalent methods like bind, chain, or then) in addition to map. - [05:07](https://www.youtube.com/watch?v=9QveBbn7t_c&t=307s) Using standard map on functions returning container structures like streams causes nested wrapping (Stream<Stream<Value>>), whereas flatMap flattens and unwraps the inner value. - [08:10](https://www.youtube.com/watch?v=9QveBbn7t_c&t=490s) JavaScript Promises act as monads through .then(), which automatically unwraps nested promises returned within its callback.
## Key takeaways - [00:00](https://www.youtube.com/watch?v=9QveBbn7t_c&t=0s) Monads build directly on functors, requiring an understanding of functors before tackling monads. - [00:00](https://www.youtube.com/watch?v=9QveBbn7t_c&t=0s) While a functor is an object implementing map, a monad is a functor that also implements flatMap. - [00:00](https://www.youtube.com/watch?v=9QveBbn7t_c&t=0s) MPJ advocates prioritizing intuitive, practical utility over getting bogged down in academic category theory and Haskell-specific laws. - [01:42](https://www.youtube.com/watch?v=9QveBbn7t_c&t=102s) Reactive streams in libraries like Bacon.js, RxJS, and Highland act as functors by supporting transformations via .map(). - [01:42](https://www.youtube.com/watch?v=9QveBbn7t_c&t=102s) Asynchronous operations returning promises can be integrated into reactive workflows using wrappers like Bacon.fromPromise(). - [05:07](https://www.youtube.com/watch?v=9QveBbn7t_c&t=307s) Applying regular .map() to an asynchronous operation that returns another stream produces nested stream objects rather than actual values. - [05:07](https://www.youtube.com/watch?v=9QveBbn7t_c&t=307s) The flatMap method resolves nesting by awaiting inner stream emission and unwrapping the contained value before forwarding it. - [08:10](https://www.youtube.com/watch?v=9QveBbn7t_c&t=490s) ECMAScript Promises effectively behave as monads because .then() automatically flattens nested promises returned by callbacks. - [08:10](https://www.youtube.com/watch?v=9QveBbn7t_c&t=490s) The flattening operation known as flatMap is referred to as bind in Haskell, chain in Fantasy Land libraries, and then in JavaScript Promises. - [08:10](https://www.youtube.com/watch?v=9QveBbn7t_c&t=490s) Once flattened, stream values can immediately be chained back into standard functor transformations like .map().
## Detailed walkthrough ### [00:00](https://www.youtube.com/watch?v=9QveBbn7t_c&t=0s) Demystifying the Monad: Practical Understanding Over Haskell Theory
MPJ opens the episode by emphasizing that monads build directly on the concept of functors, meaning viewers must understand functors first for the discussion to make any sense. While a functor is fundamentally an object or data structure that implements `map`, a monad is simply a more powerful functor that also implements `flatMap`.
MPJ issues a warning about how monads are commonly taught across the internet. He points out that most existing material gets hopelessly bogged down in mathematical precision, rigid category theory laws, and Haskell-specific implementations. MPJ explains his philosophy for cutting through the academic jargon: “I think that doing it with that level of detail and correctness is going to cause you to not see the forest for all the trees so we're not going to do that in this video.” Rather than memorizing abstract monad laws upfront, the goal is to give developers a clear, intuitive sense of what a monad is and how it solves everyday programming problems. Once that practical mental model clicks, the deeper theoretical details can always be learned later.
```mermaid flowchart LR accTitle: Hierarchy of Functors and Monads accDescr: Visual diagram showing that Monad is a specialized Functor implementing both map and flatMap.
subgraph FunctorSpace["Functor Interface"] F["Functor"] -->|"implements"| M["map()"] end
subgraph MonadSpace["Monad Interface"] MO["Monad"] -->|"inherits / implements"| M2["map()"] MO -->|"additionally implements"| FM["flatMap() / then / bind / chain"] end ```
[01:42](https://www.youtube.com/watch?v=9QveBbn7t_c&t=102s) Functors with Bacon.js Streams and Translating Words
To understand why `flatMap` is necessary and what is actually "flat" about it, MPJ demonstrates working with reactive event streams using Bacon.js. While Bacon.js is used here, he notes that stream concepts are identical across other reactive programming libraries like RxJS or Highland.
MPJ creates a Bacon `Bus`, which represents the simplest form of stream in Bacon.js. By calling `stream.onValue(callback)`, the provided callback executes whenever an item is emitted. When three strings—`"cat"`, `"meal"`, and `"trumpet"`—are pushed into the bus, `console.log` immediately prints each word. Because streams are functors, they support `.map()`. MPJ illustrates this by transforming each incoming item with `.map(word => word.toUpperCase())`, which instantly outputs `"CAT"`, `"MEAL"`, and `"TRUMPET"`.
Next, MPJ elevates the example to a realistic asynchronous task: using the Google Translate API to translate each word into Portuguese. He mentions as a brief aside that he will be speaking in August at BrazilJS, the world's largest JavaScript conference. He constructs a helper function called `getInPortuguese(word)` that issues an HTTP GET request via the Fetch API. Because Fetch returns an ES6 promise while the rest of the application runs on Bacon.js, MPJ bridges the two by passing the promise into `Bacon.fromPromise(promise)`. This allows `getInPortuguese` to return a Bacon stream that emits the translated word once the network request finishes.
[05:07](https://www.youtube.com/watch?v=9QveBbn7t_c&t=307s) The Problem with Nested Streams and the Need for `flatMap`
When MPJ attempts to connect the bus stream to the translation helper using regular `.map()`, everything breaks down:
```javascript stream .map(word => getInPortuguese(word)) .onValue(word => console.log(word)); ```
Instead of printing the translated strings, running the program outputs stream instances. Because `getInPortuguese` itself returns a stream, mapping over the input stream results in a stream containing inner streams. As MPJ humorously laments: “Functor and map you have failed us.”
```mermaid flowchart TD accTitle: Map versus FlatMap behavior on nested streams accDescr: Comparison diagram showing how map produces nested streams whereas flatMap unwraps inner values.
subgraph MapFlow["Stream.map(getInPortuguese)"] A["'cat'"] --> B["map()"] B --> C["Stream (Stream <'gato'>)"] C --> D["Output: [Bacon Stream Object]"] end
subgraph FlatMapFlow["Stream.flatMap(getInPortuguese)"] E["'cat'"] --> F["flatMap()"] F --> G["Stream <'gato'> (unwrapped)"] G --> H["Output: 'gato'"] end ```
This is the exact problem monads are designed to resolve. MPJ replaces `.map()` with `.flatMap()`, and the application suddenly logs the actual Portuguese translations. FlatMap intercepts the inner stream returned by `getInPortuguese`, waits for it to emit its value, unwraps (flattens) that contained value out of the stream container, and forwards the bare value to the downstream `.onValue()` listener. When MPJ temporarily switches the code back to `.map()` to prove the contrast, the console reverts to spewing raw Bacon stream objects. Switching back to `.flatMap()` immediately restores the unwrapped strings.
- Calling `.map()` on a functor that returns another functor creates unwanted nesting: `Stream<Stream<Value>>`. - Calling `.flatMap()` automatically unpacks the inner functor into a single flat stream: `Stream<Value>`.
[08:10](https://www.youtube.com/watch?v=9QveBbn7t_c&t=490s) Monads Under Other Names: Promises, `.then()`, `chain`, and `bind`
MPJ addresses a common point of confusion among JavaScript developers: whether native Promises are monads. While promises lack a method literally named `flatMap`, their `.then()` method acts as a `flatMap` in disguise. When a function passed to `.then()` returns another promise, `.then()` automatically unwraps that promise rather than nesting it.
MPJ illustrates this by looking at how `fetch()` operates:
```javascript fetch(url) .then(response => response.json()) .then(parsedResponse => {... }); ```
Calling `response.json()` does not return a raw object literal; it returns another Promise. The surrounding `.then()` automatically flattens that promise down to the resolved parsed JSON object before handing it to the subsequent `.then()` callback.
MPJ clarifies that the functional programming community uses several names for the exact same flattening operation: - `flatMap` (common in modern JavaScript and stream libraries like Bacon.js and RxJS) - `bind` (standard Haskell terminology) - `chain` (common in Fantasy Land and algebraic JavaScript libraries) - `then` (standard ECMAScript Promises)
Because the flattened stream outputs clean word values, it can immediately be chained back into regular functor operations like `.map(word => word.toUpperCase())`. In summary: “flat map has the same principle as map with the exception that if the callback pass to flat map returns a monad of the same type you know if if stream if you're calling flat map on stream it returns a stream monad that stream monad will be flattened into its containing value before it's it's passed on”.
MPJ wraps up by inviting viewers to share their lingering questions and confusion in the comments for an upcoming follow-up video, reminding the audience that new episodes drop every Monday morning at 08:00 GMT.
## Mentioned Fun Fun Function, MPJ, Haskell, Bacon.js, RxJS, Highland, Google Translate API, BrazilJS, Fetch API, Fantasy Land, @drboolean, CircleCI, Quokka
## Video description 💖 Support the show by becoming a Patreon https://www.patreon.com/funfunfunction
Monads is a type of Functor, so you need to know what a Functor is in order for this episode to make sense. Thankfully, there there is a FunFunFunction episode for that, and you can watch it here: So, what is a monad? Remember that a Functor is an object that implements *map*? Well, a monad is a more powerful functor that also implements *flatMap*.
Code from the episode https://gist.github.com/mpj/ca167aad371c67372f3b
Mad props to @drboolean for helping me to understand Monads. Besides following him on Twitter, you should watch his awesome “Classroom Coding with Prof. Frisby Pt1” https://www.youtube.com/watch?v=h_tkIpwbsxY&list=PLK_hdtAJ4KqX0JOs_KMAmUNTNMRYhWEaC
Quick intro to Fetch API http://www.sitepoint.com/introduction-to-the-fetch-api/
BaconJS https://baconjs.github.io/
Google Translate API https://cloud.google.com/translate/v2/getting_started
💛 Follow on Twitch and support by becoming a Subscriber We record the show live Mondays 7 AM PT https://twitch.tv/funfunfunction
💛 Fun Fun Forum Private discussion forum with other viewers in between shows. https://www.funfunforum.com. Available to patron members, become one at https://www.patreon.com/funfunfunction
💛 mpj on Twitter https://twitter.com/mpjme
💛 CircleCI (Show sponsor) Robust and sleek Docker-based Continuous Integration as a service. I used CircleCI prior to them becoming a sponsor and I love that their free tier is powerful enough for small personal projects, even if they are private. Use this link when you sign up to let them know you came from here: https://circleci.funfunfunction.com
💛 Quokka (Show sponsor) Wonder how MPJ evaluates JavaScript inline his editor. Quokka is the answer - use this link when you buy to let them know you came from here: http://quokka.funfunfunction.com
💛 FUN FUN FUNCTION Since 2015, Fun Fun Function (FFF) is one of the longest running weekly YouTube shows on programming 🏅 thanks to its consistency and quality reaching 200,000+ developers.
🤦♂️ The Failing Together concept is what makes FFF unique. Most coding content out there focus on step-by-step tutorials. We think tutorials are too far removed from what everyday development is like. Instead, FFF has created a completely new learning environment where we grow from failure, by solving problems while intensively interacting with a live audience.
Tutorials try to solve a problem. Failing Together makes you grow as a developer and coworker.
📹 Each show is recorded live on Twitch in a 2-hour livestream on Mondays. The host, assisted by the audience, is tasked to complete a programming challenge by an expert guest. Like in the real world, we often fail, and learn from it. This, of course, reflects what the audience identifies with, and is one of the most praised aspects of the show.
⏯ On Fridays, an edited version of the show is adapted for and published on YouTube.
Content Topics revolve around: JavaScript, Functional Programming, Software Architecture, Quality Processes, Developer Career and Health, Team Collaboration, Software Development, Project Management
[Source](https://www.youtube.com/watch?v=9QveBbn7t_c)