One Line, Six Layers

"Simple things should be simple, complex things should be possible."

– Alan Kay


Here is a single line of Higher-Kinded-J. It is the entire body of a service method that edits one attribute on one node in a repository.

repo.find(id)
    .toEitherPath()
    .focus().attributes().at(key)
    .modify(spec::validateAndCoerce)
    .flatMap(repo::save);

That is it. No null check, no try/catch, no nested if, no copy constructor, no explicit error mapping. The same skeleton works unchanged for reparent, retag, override, and restore. Change the verb in the middle and the line still reads like a sentence.

Foundations is the chapter where we explain why this composes. Before we begin, let us see how much of the library is hiding inside those eighty characters.

What We'll Learn

  • Why this one line is a good map of the whole stack
  • Which Foundations concept lights up at each token
  • Which reading path through the chapter best fits our goals

Six Layers in One Expression

Each token in the line corresponds to a layer that the rest of this chapter unpacks.

   repo.find(id)              .toEitherPath()      .focus().attributes().at(key)
   └── Effect Path ───────────┤                    └── Optic ──────────────────┐
       absence as MaybePath   │                        traversal into a record │
                              │                                                │
                              └── Natural transformation                       │
                                  MaybePath ~> EitherPath                      │
                                                                               │
   .modify(spec::validateAndCoerce)             .flatMap(repo::save);          │
   └── Functor (under the optic) ───┐           └── Monad ─────────────────────┘
       pure transform on the focus  │               sequencing dependent steps
                                    │               (Either short-circuits)
                                    │
                                    └── Type class instance dispatched at compile time
                                        EitherFunctor / EitherMonad

Six independent ideas, none of which needed to be wired together by hand.

TokenLayerWhere in this chapter
repo.find(id)A concrete instance of an effect typeCore Types
.toEitherPath()A natural transformation between effectsNatural Transformation
.focus().attributes().at(key)A profunctor optic composed from lens and traversalProfunctor, Optics chapter
.modify(spec::validateAndCoerce)A Functor map running through the opticFunctor
.flatMap(repo::save)The Monad instance for EitherPathMonad
The whole expressionA Kind<F, A> flowing through type-class methodsHigher-Kinded Types

Notice that we never had to pick a strategy for "what happens on failure". EitherPath already encodes failure as a left rail, and every operation downstream of a failing step quietly skips itself. The interesting code is in the middle, where the domain logic lives.


The Same Skeleton, Different Verbs

The promise of this style is that once we have the skeleton, the variations are almost free. The snippets below are illustrative; the exact focus() method names depend on what the Optics chapter generates for our domain records.

// Edit one field
repo.find(id)
    .toEitherPath()
    .focus().attributes().at(key)
    .modify(spec::validateAndCoerce)
    .flatMap(repo::save);

// Move a node under a new parent
repo.find(id)
    .toEitherPath()
    .focus().parent()
    .replace(newParentId)
    .flatMap(repo::save);

// Add a tag, without disturbing the rest of the record
repo.find(id)
    .toEitherPath()
    .focus().tags()
    .modify(tags -> tags.add(tag))
    .flatMap(repo::save);

// Restore from a snapshot
repo.findSnapshot(id, version)
    .toEitherPath()
    .flatMap(repo::save);

Four operations, one shape. The repeated structure is not duplication; it is the API. Foundations explains the abstractions that make that possible.


How to Read the Rest of This Chapter

Foundations is not a tutorial; it is the engine-room tour for readers who have already been productive with the library and want to know what is humming under the floor.

We have written it so that three different readers can take three different routes through it.

Three Reading Paths

The mechanism tour (≈ 30 minutes)

For readers who want to lift the bonnet on the line above and see how Kind<F, A>, witness types, and type-class instances cooperate at runtime.

  1. HKT Introduction
  2. Core Concepts
  3. Lifting the Hood, an annotated trace of one flatMap call from user code through widen, dispatch, and narrow
  4. Functor, Monad, and MonadError, each with a "Back to the one-liner" callout
  5. Foundations FAQ for the questions experienced Java readers ask

The generic-code author (≈ 45 minutes)

For readers who want to write code that works unchanged across MaybePath, EitherPath, TryPath, and friends.

  1. Usage Guide
  2. FunctorApplicativeMonadTraverse
  3. Natural Transformation
  4. The cookbook recipes scattered through Type Classes

The library extender (≈ 60 minutes)

For readers who want to give their own type a witness, widen/narrow, and a Monad instance, so that it joins the same composition story.

  1. Core Concepts
  2. Type Arity
  3. Extending the Simulation
  4. The "Things People Get Wrong" callouts in the Type Classes section

What Foundations Is, and Is Not

Foundations is not a sales pitch. We assume the reader has already shipped code with the Effect Path API, or with Optics, or with Monad Transformers, and is here for depth rather than motivation.

Foundations is the chapter that explains why the eighty characters above hold together, and how to write our own eighty characters that do the same job for our own domain.

Everything that follows is, in some sense, a footnote on that one line.


Next: Higher-Kinded Types