# For-Comprehensions

~~~admonish info title="What You'll Learn"
- How to transform nested `flatMap` chains into readable, sequential code
- The four types of operations: generators (`.from()`), bindings (`.let()`), guards (`.when()`), and projections (`.yield()`)
- Building complex workflows with StateT and other monad transformers
- Converting "pyramid of doom" code into clean, imperative-style scripts
~~~

~~~ admonish example title="See Example Code:"
[ForComprehensionExample.java](https://github.com/higher-kinded-j/higher-kinded-j/blob/main/hkj-examples/src/main/java/org/higherkindedj/example/basic/expression/ForComprehensionExample.java)
~~~

~~~admonish title="Hands On Practice"
[Tutorial03_ForTraverseComprehension.java](https://github.com/higher-kinded-j/higher-kinded-j/blob/main/hkj-examples/src/test/java/org/higherkindedj/tutorial/expression/Tutorial03_ForTraverseComprehension.java)
~~~

Endless nested callbacks and unreadable chains of flatMap calls can be tiresome. The `higher-kinded-j` library brings the elegance and power of Scala-style for-comprehensions to Java, allowing you to write complex asynchronous and sequential logic in a way that is clean, declarative, and easy to follow.

Let's see how to transform "callback hell" into a readable, sequential script.

## The "Pyramid of Doom" Problem

In functional programming, monads are a powerful tool for sequencing operations, especially those with a context like `Optional`, `List`, or `CompletableFuture`. However, chaining these operations with `flatMap` can quickly become hard to read.

Consider combining three `Maybe` values:

<!-- verify -->
```java
// The "nested" way
Kind<MaybeKind.Witness, Integer> result = maybeMonad.flatMap(a ->
    maybeMonad.flatMap(b ->
        maybeMonad.map(c -> a + b + c, maybeC),
    maybeB),
maybeA);
```

This code works, but the logic is buried inside nested lambdas. The intent (to simply get values from `maybeA`, `maybeB`, and `maybeC` and add them) is obscured. This is often called the "pyramid of doom."

## _For_ A Fluent, Sequential Builder

The `For` comprehension builder provides a much more intuitive way to write the same logic. It lets you express the sequence of operations as if they were simple, imperative steps.

Here's the same example rewritten with the `For` builder:

<!-- verify -->
```java
import static org.higherkindedj.hkt.maybe.MaybeKindHelper.MAYBE;
import org.higherkindedj.hkt.expression.For;
// ... other imports

var maybeMonad = Instances.monadError(maybe());
var maybeA = MAYBE.just(5);
var maybeB = MAYBE.just(10);
var maybeC = MAYBE.just(20);

// The clean, sequential way
var result = For.from(maybeMonad, maybeA)    // Get a from maybeA
    .from(a -> maybeB)                       // Then, get b from maybeB
    .from(t -> maybeC)                       // Then, get c from maybeC
    .yield((a, b, c) -> a + b + c);          // Finally, combine them

System.out.println(MAYBE.narrow(result)); // Prints: Just(35)
```

This version is flat, readable, and directly expresses the intended sequence of operations. The `For` builder automatically handles the `flatMap` and `map` calls behind the scenes.

~~~admonish note title="Supported Arities"
The `For` builder supports up to **12 chained bindings** (generators, value bindings, or focus/match operations). Step 1 is hand-written; steps 2-12 are generated by the `hkj-processor` annotation processor. Both the spread-style yield (`(a, b, c, ...) -> result`) and tuple-style yield (`tuple -> result`) are supported at all arities.
~~~

### Extended Arity Example (6+ Bindings)

The generated `Steps2`-`Steps12` classes provide the same fluent API seamlessly:

<!-- verify -->
```java
var idMonad = Instances.monad(id());

Kind<IdKind.Witness, String> result =
    For.from(idMonad, Id.of("Alice"))       // a = "Alice"
        .let(name -> name.length())          // b = 5
        .from(t -> Id.of(t._1().toUpperCase())) // c = "ALICE"
        .let(t -> t._2() * 10)              // d = 50
        .let(t -> t._3() + "!")             // e = "ALICE!"
        .let(t -> t._1() + " has " + t._2() + " letters")  // f = summary
        .yield((name, len, upper, score, exclaimed, summary) ->
            summary + " (score: " + score + ")");

// Result: "Alice has 5 letters (score: 50)"
```

At higher arities, the tuple-style `yield` is especially convenient for accessing accumulated values by position:

```java
.yield(t -> t._6() + " (score: " + t._4() + ")")
```

~~~admonish tip title="Consider toState() for complex workflows"
As the number of bindings grows, tuple positions like `t._3()` and `t._4()` become hard to track. The `toState()` bridge lets you gather values with `For`, then transition to named fields for the rest. See [Bridging to ForState](for_mtl.md#bridging-to-forstate-with-tostate) for details.
~~~

## Core Operations of the `For` Builder

A for-comprehension is built by chaining four types of operations:

### 1. Generators: `.from()`

A generator is the workhorse of the comprehension. It takes a value from a previous step, uses it to produce a new monadic value (like another `Maybe` or `List`), and extracts the result for the next step. This is a direct equivalent of **`flatMap`**.

Each `.from()` adds a new variable to the scope of the comprehension.

<!-- verify -->
```java
// Generates all combinations of userLogin IDs and roles
var userRoles = For.from(listMonad, LIST.widen(List.of("userLogin-1", "userLogin-2"))) // a: "userLogin-1", "userLogin-2"
    .from(a -> LIST.widen(List.of("viewer", "editor")))       // b: "viewer", "editor"
    .yield((a, b) -> a + " is a " + b);

// Result: ["userLogin-1 is a viewer", "userLogin-1 is a editor", "userLogin-2 is a viewer", "userLogin-2 is a editor"]
```


### 2. Value Bindings: `.let()`

A `.let()` binding allows you to compute a pure, simple value from the results you've gathered so far and add it to the scope. It does *not* involve a monad. This is equivalent to a **`map`** operation that carries the new value forward.

<!-- verify -->
```java
var idMonad = Instances.monad(id());

var result = For.from(idMonad, Id.of(10))        // a = 10
    .let(a -> a * 2)                          // b = 20 (a pure calculation)
    .yield((a, b) -> "Value: " + a + ", Doubled: " + b);

// Result: "Value: 10, Doubled: 20"
System.out.println(ID.narrow(result).value());
```


### 3. Guards: `.when()`

For monads that can represent failure or emptiness (like `List`, `Maybe`, or `Optional`), you can use `.when()` to **filter** results. If the condition is false, the current computational path is stopped by returning the monad's "zero" value (e.g., an empty list or `Maybe.nothing()`).

> This feature requires a `MonadZero` instance. See the `MonadZero` documentation for more details.
>

<!-- verify -->
```java
var evens = For.from(listMonad, LIST.widen(List.of(1, 2, 3, 4, 5, 6)))
    .when(i -> i % 2 == 0) // Guard: only keep even numbers
    .yield(i -> i);

// Result: [2, 4, 6]
```



### 4. Projection: `.yield()`

Every comprehension ends with `.yield()`. This is the final **`map`** operation where you take all the values you've gathered from the generators and bindings and produce your final result. You can access the bound values as individual lambda parameters or as a single `Tuple`.

## Turn the power up: `StateT` Example

- [ForComprehensionExample.java](https://github.com/higher-kinded-j/higher-kinded-j/blob/main/hkj-examples/src/main/java/org/higherkindedj/example/basic/expression/ForComprehensionExample.java)

The true power of for-comprehensions becomes apparent when working with complex structures like monad transformers. A `StateT` over `Optional` represents a **stateful computation that can fail**. Writing this with nested `flatMap` calls would be extremely complex. With the `For` builder, it becomes a simple, readable script.

<!-- verify -->
```java
import static org.higherkindedj.hkt.optional.OptionalKindHelper.OPTIONAL;
import static org.higherkindedj.hkt.state_t.StateTKindHelper.STATE_T;
// ... other imports

private static void stateTExample() {
    final var optionalMonad = Instances.monadError(optional());
    final var stateTMonad =
        Instances.<Integer, OptionalKind.Witness>stateT(optionalMonad);

    // Helper: adds a value to the state (an integer)
    final Function<Integer, Kind<StateTKind.Witness<Integer, OptionalKind.Witness>, Unit>> add =
        n -> StateT.create(s -> optionalMonad.of(StateTuple.of(s + n, Unit.INSTANCE)));

    // Helper: gets the current state as the value
    final var get = StateT.<Integer, OptionalKind.Witness, Integer>create(s -> optionalMonad.of(StateTuple.of(s, s)));

    // This workflow looks like a simple script, but it's a fully-typed, purely functional composition!
    final var statefulComputation =
        For.from(stateTMonad, add.apply(10))      // Add 10 to state
            .from(a -> add.apply(5))              // Then, add 5 more
            .from(b -> get)                       // Then, get the current state (15)
            .let(t -> "The state is " + t._3())   // Compute a string from it
            .yield((a, b, c, d) -> d + ", original value was " + c); // Produce the final string

    // Run the computation with an initial state of 0
    final var resultOptional = STATE_T.runStateT(statefulComputation, 0);
    final Optional<StateTuple<Integer, String>> result = OPTIONAL.narrow(resultOptional);

    result.ifPresent(res -> {
        System.out.println("Final value: " + res.value());
        System.out.println("Final state: " + res.state());
    });
    // Expected Output:
    // Final value: The state is 15, original value was 15
    // Final state: 15
}
```

In this example, Using the `For` comprehension really helps hide the complexity of threading the state (`Integer`) and handling potential failures (`Optional`), making the logic clear and maintainable.


For a more extensive example of using the full power of the For comprehension head over to the [Order Workflow](../hkts/order-walkthrough.md)

## Similarities to Scala

If you're familiar with Scala, you'll recognise the pattern. In Scala, a for-comprehension looks like this:

```scala
for {
 a <- maybeA
 b <- maybeB
 if (a + b > 10)
 c = a + b
} yield c * 2
```

This is built in syntactic sugar that the compiler translates into a series of `flatMap`, `map`, and `withFilter` calls.
The `For` builder in `higher-kinded-j` provides the same expressive power through a method-chaining API.

---

~~~admonish info title="Hands-On Learning"
- [Tutorial 02: ForPath Parallel Composition](../tutorials/expression/forpath_parallel_journey.md) (9 exercises).
~~~

~~~admonish tip title="Further Reading"
- **Project Reactor**: [Mono and Flux Composition](https://projectreactor.io/docs/core/release/reference/) - Java's reactive library uses similar chaining patterns for composing asynchronous operations
- **Baeldung**: [Java CompletableFuture](https://www.baeldung.com/java-completablefuture) - Java's built-in approach to chaining dependent asynchronous steps
~~~

~~~admonish tip title="See Also"
- [Parallel Composition](for_par.md) - Express independent computations with `par()`
- [Traverse Within Comprehensions](for_traverse.md) - Bulk operations over traversable structures
- [Optics Integration](for_optics.md) - `focus()`, `match()`, ForTraversal, and ForIndexed
- [MTL & ForState Bridge](for_mtl.md) - MTL integration and `toState()` bridge
- [ForState: Named State Comprehensions](forstate_comprehension.md) - The recommended pattern for complex workflows
- [ForPath Comprehension](../effect/forpath_comprehension.md) - For-comprehensions that work directly with Effect Path types
~~~

---

**Previous:** [Natural Transformation](natural_transformation.md) | **Next:** [Parallel Composition](for_par.md)
