Monads: sequencing dependent steps
The monad has the worst ratio of mystery to substance in all of programming. The substance: flatMap (also called bind) is the operation for sequencing a step whose result decides what happens next. Citizen lookup produces facts; whether you then query the land registry depends on those facts. That dependence — each step chosen by the previous step’s output — is what separates monadic sequencing from applicative combination.
Why map is not enough
Suppose the registry returns Result and the mapper also returns Result:
Result<CitizenFacts, RegistryError> facts = registry.loadCitizen(citizenId);// next step needs the CitizenFacts, and itself produces a Result:// facts.map(facts -> land.loadLandRecord(facts.citizenId()))// : Result<Result<LandRecord, RegistryError>, RegistryError> ← nested, uselessmap wraps the mapper’s output in another context, so the failure channel doubles. flatMap collapses the nesting by being defined as “map, then flatten”:
flatMap : M<A> → (A → M<B>) → M<B>The implementations, again
You already saw them inside the records — look at them now as the monad’s two cases:
// Success.flatMap: the chain continuespublic <R> Result<R, E> flatMap(Fn1<? super T, ? extends Result<R, E>> mapper) { return mapper.apply(value);}
// Failure.flatMap: the chain is already overpublic <R> Result<R, E> flatMap(Fn1<? super T, ? extends Result<R, E>> mapper) { return new Failure<>(error);}A failure anywhere upstream means every later flatMap is a no-op pass-through — the short-circuit is structural, not an if you have to remember to write.
Scheme example: the dependent chain
public Result<EligibilityOutcome, RegistryError> evaluate(String citizenId) { return citizens.loadCitizen(citizenId) .flatMap(facts -> land.loadLandRecord(citizenId) .map(record -> FarmerSupportPolicy.evaluate(facts, scheme)));}The last step is map, not flatMap, because evaluate returns a plain EligibilityOutcome — the rule of thumb is the one from the series outline: map when the function returns an ordinary value, flatMap when it returns a context.
Where the word comes from
Moggi (1989) proposed monads as a way to give denotational semantics to effectful programs; Wadler (1990s) carried them into Haskell as the practical mechanism for I/O and state. The “monad” itself is the pair of operations — pure (wrap a plain value) and flatMap — satisfying the three laws Part 10 tests. Every type you have built that has a lawful pure/flatMap pair — Option, Result, and later IO, Reader, State — is one.
The pitfall the chapter exists for: do not reach for flatMap reflexively. Independent checks deserve Validated (Part 8); a chain where no step consumes the previous result is applicative-shaped, and forcing it through bind just hides that you could have run the steps in parallel — which matters in Part 18.