Decision Trees

Three trees, one page

What You'll Learn

  • Which optic type to choose for a given data shape and access pattern.
  • Which API style (Focus DSL, manual composition, Fluent API, Free Monad DSL) to choose for a given task.
  • Which advanced feature (filtered, indexed, profunctor) solves which specific problem.

The decision trees that appear in scattered form across the chapter intros are consolidated here. Use this page when you need to route quickly to the right tool.


Tree 1: Which optic do I need?

                     ┌─────────────────────┐
                     │ What are you doing? │
                     └──────────┬──────────┘
                                │
           ┌────────────────────┼────────────────────┐
           ▼                    ▼                    ▼
    ┌─────────────┐     ┌─────────────┐     ┌─────────────┐
    │   Reading   │     │  Modifying  │     │ Transforming│
    │    only?    │     │   values?   │     │   types?    │
    └──────┬──────┘     └──────┬──────┘     └──────┬──────┘
           │                   │                   │
           ▼                   │                   ▼
    ┌─────────────┐            │            ┌─────────────┐
    │ How many    │            │            │     ISO     │
    │ targets?    │            │            └─────────────┘
    └──────┬──────┘            │
           │                   │
    ┌──────┴──────┐            │
    ▼             ▼            ▼
┌───────┐   ┌──────────┐  ┌─────────────┐
│ One   │   │Zero-more │  │ How many    │
│       │   │          │  │ targets?    │
└───┬───┘   └────┬─────┘  └──────┬──────┘
    │            │               │
    ▼            ▼        ┌──────┴──────┐
┌───────┐   ┌────────┐    ▼             ▼
│GETTER │   │ FOLD   │ ┌───────┐  ┌──────────┐
└───────┘   └────────┘ │ One   │  │Zero-more │
                       └───┬───┘  └────┬─────┘
                           │           │
                 ┌─────────┴───┐       │
                 ▼             ▼       ▼
           ┌──────────┐ ┌─────────┐ ┌──────────┐
           │ Required │ │Optional │ │TRAVERSAL │
           └────┬─────┘ └────┬────┘ └──────────┘
                │            │
                ▼            ▼
           ┌────────┐   ┌─────────┐
           │  LENS  │   │ PRISM   │
           └────────┘   └─────────┘
You have...You want to...Reach for
A required field on a recordGet and setLens
A variant of a sealed typeMatch and modify the variantPrism
An optional field (nullable, Optional-wrapped)Get and set if presentAffine
Two equivalent representationsConvert losslesslyIso
A collection fieldApply an operation to every elementTraversal
A collection field, read-onlyQuery, search, aggregateFold
Read-only access to a single fieldGet onlyGetter
Write-only access to a single fieldSet onlySetter

Tree 2: Which API style?

┌─────────────────────────────────────────────────────────────────────────────┐
│                        CHOOSING YOUR API                                    │
├─────────────────────────────────────────────────────────────────────────────┤
│                                                                             │
│  ┌─────────────────┐                                                        │
│  │  Focus DSL      │ ◄─── START HERE                                        │
│  │  (Recommended)  │      Path-based navigation with full type safety       │
│  └────────┬────────┘      CompanyFocus.departments().employees().name()     │
│           │                                                                 │
│           │  Need validation-aware modifications?                           │
│           │  Working with Either/Maybe/Validated?                           │
│           ▼                                                                 │
│  ┌─────────────────┐                                                        │
│  │  Fluent API     │      Static methods + builders for effectful ops       │
│  │  (OpticOps)     │      OpticOps.modifyEither(user, lens, validator)      │
│  └─────────────────┘                                                        │
│                                                                             │
│  Need audit trails, dry-runs, or multiple execution strategies?             │
│  See Advanced Optics for the Free Monad DSL.                                │
│                                                                             │
└─────────────────────────────────────────────────────────────────────────────┘
Your taskUse
Update a nested record fieldFocus DSL
Compose optics across types you ownFocus DSL
Validate as you modify (Either, Validated, Maybe)Fluent API
Fan out an effect across a collectionFluent API modifyAllF
Build optic operations as data, run laterFree Monad DSL
Audit trail of every optic operationFree Monad DSL with logging interpreter
Reuse an optic for a type you cannot annotate@ImportOptics or an OpticsSpec interface
Adapt an optic to a different data shapeProfunctor contramap / map / dimap

Tree 3: Which advanced feature?

                  ┌─────────────────────────────┐
                  │ What is the constraint?     │
                  └──────────────┬──────────────┘
                                 │
        ┌────────────────────────┼────────────────────────┐
        ▼                        ▼                        ▼
   ┌──────────┐           ┌────────────┐           ┌──────────────┐
   │ Subset   │           │ Position   │           │ Type adapter │
   │ matters  │           │ matters    │           │ for source/  │
   │          │           │            │           │ target       │
   └────┬─────┘           └─────┬──────┘           └──────┬───────┘
        │                       │                         │
        ▼                       ▼                         ▼
   ┌──────────┐           ┌────────────┐           ┌──────────────┐
   │ Filtered │           │  Indexed   │           │  Profunctor  │
   │ optics   │           │  optics    │           │  optics      │
   └──────────┘           └────────────┘           └──────────────┘
Your problemReach for
"Apply only to elements matching a predicate"Filtered Optics
"I need the index alongside each element"Indexed Optics
"Access by key in a Map"Indexed Access and the At typeclass
"Apply over every element of a custom container"Each Typeclass
"Operate on individual characters of a String"String Traversals
"Adapt a lens for a different source record type"lens.contramap(...) (Profunctor Optics)
"Adapt a lens for a different target type"lens.map(...) (Profunctor Optics)
"Both source and target need adapting"lens.dimap(...) (Profunctor Optics)
"Match a sum-type variant by a predicate, not type"Advanced Prism Patterns: nearly and doesNotMatch

See also


Previous: Production Readiness