| title | Chaining Computations with flatMap | |||||||
|---|---|---|---|---|---|---|---|---|
| id | combinator-flatmap | |||||||
| skillLevel | beginner | |||||||
| applicationPatternId | core-concepts | |||||||
| summary | Use flatMap to chain together computations where each step may itself be effectful, optional, or error-prone. | |||||||
| tags |
|
|||||||
| rule |
|
|||||||
| related |
|
|||||||
| author | PaulJPhilp | |||||||
| lessonOrder | 2 |
Use the flatMap combinator to chain together computations where each step may itself return an Effect, Stream, Option, or Either.
flatMap ensures that the result is always "flattened"—you never get nested types.
flatMap is the key to sequencing dependent steps in functional programming.
It allows you to express workflows where each step may fail, be optional, or produce multiple results, and ensures that errors and context are handled automatically.
import { Effect, Stream, Option, Either } from "effect";
// Effect: Chain two effectful computations
const effect = Effect.succeed(2).pipe(
Effect.flatMap((n) => Effect.succeed(n * 10))
); // Effect<number>
// Option: Chain two optional computations
const option = Option.some(2).pipe(Option.flatMap((n) => Option.some(n * 10))); // Option<number>
// Either: Chain two computations that may fail
const either = Either.right(2).pipe(
Either.flatMap((n) => Either.right(n * 10))
); // Either<never, number>
// Stream: Chain streams (flattening)
const stream = Stream.fromIterable([1, 2]).pipe(
Stream.flatMap((n) => Stream.fromIterable([n, n * 10]))
); // Stream<number>Explanation:
flatMap lets you build pipelines where each step can depend on the result of the previous one, and the structure is always flattened—no Option<Option<A>> or Effect<Effect<A>>.
Manually unwrapping the value (e.g., with .getOrElse, .unsafeRunSync, etc.), then creating a new effect/option/either/stream.
This breaks composability, loses error/context handling, and leads to deeply nested or unsafe code.