cats-eo

Cookbook

Optics are probably the most powerful unused tool in our arsenal — this section is the working proof. Runnable patterns for the questions that come up most often, one page for each of the three jobs optics do best:

  1. Navigating structures — reach one branch of a sum, every node of a recursive tree, several fields at once, or a field inside bytes you never decode. One .andThen surface for all of it.
  2. Decoupling and modularity — replace a direct dependence on a data type with an optic: depend on the relationship, ask for the weakest capability you need, and let independent modules interoperate at the call site.
  3. Effect threading — turn control flow into type definitions: the optic pins where, the effect type decides what happens — abort, accumulate, audit, defer.

Two demos open the section: whole programs, with their own tests and benchmarks, that put these recipes to work.

The framing follows Hansen — We Need More Optics (https://medium.com/swlh/we-need-more-optics-8ddf1d2d9468) and Penner — Optics By Example (https://leanpub.com/optics-by-example/). These are worked examples, not a tutorial — for the optic families themselves see the Optics reference. Every recipe cites its source.

If you arrive with a task rather than an optic in mind, start here:

I want to… Recipe
edit one branch of a sum type, misses passing through Visit contingent fields
apply one edit at every node of a recursive tree Visit across whole trees
update only the matching elements of a collection Visit through arbitrary structure
fold several fields into one number Isolate what you need
rewrite every slot of a fixed shape, or summarise a batch Compute aggregations
update a grid coordinate or preserve device labels Indexed: Grates and Glasses
change a field deep in JSON without decoding the payload Edit JSON without decoding
depend on a relationship instead of a data type Require the optic, not the type
ask for the weakest capability a function needs Depend only on what's needed
edit Avro bytes on a hot path, no decode Serdes free pipes
move one field between wire formats (Avro ↔ JSON) Inspectable cross-format bridges
law-test the optics my module publishes Re-usable laws for testing
make an in-place update fallible Validate-in-place with modifyF
swap abort / accumulate / audit without touching the optic Structure orthogonal to effects
batch N+1 lookups through one traversal Batch-load nested IDs
stamp an effect's result back into the entity Persist-and-stamp decode free

Further reading