Refactoring 2/35: Replace mutable fields with lenses - #13
Merged
Merged
Conversation
Second entry of the refactoring catalogue, with its dual (inline the lens). Three Before/After examples in Scala 3 and Haskell, each proven equivalent by hedgehog properties the reviewer mutation-checked, plus the three lens laws as second properties, a koan diagram and three example diagrams, and 14 references verified against primary sources. - pages/refactorings/replace-mutable-fields-with-lenses.md and /sources/ - _data/refactorings.yml: add slug for the entry - _config.yml: exclude the new sources dir - .claude/skills/refactoring-entry/LESSONS.md: lessons from this entry (result-value comparison, composed-path design, partial-lens pitfall)
Contributor
|
- Examples rebuilt around the eo cookbook navigate-structures trio: prism×lens on one node, the same optic at every tree node, and a traversal×prism×lens sparse walk over a batch — all self-contained optic encodings running in both Scala 3 and Haskell with no deps. - Page rewritten: optics framing (how-to-reach vs what-to-do), lawful by construction + law-solvers, inverse justified by decoupling not being worth it / no cross-domain boundaries, functional reading as optics (links eo), pitfalls are accidental complexity + rebuilding beyond the focus, verification cites cats-eo-laws / monocle-law / genvalidity-hspec-optics. - All 12 properties pass both languages; mutants caught. - Diagrams redrawn for the three new examples.
- Move the optic building blocks (Lens/Prism/PartialLens/each) and the hedgehog spec runner out of the examples into pages/.../shared/, compiled by run.sh (scala-cli sources + runghc -i) but never shown on the page. Each Before/After/Spec is now the move itself; the page notes the shared setup is hidden. - SKILL.md/brief.md: fold in the rule (shared setup is accidental complexity if shown; hide it in non-published shared/), and generalize the skill for any agent — the workflow is described as phases (research · examples · review · diagrams), with the Claude Workflow script as one optional orchestrator and the gh step generalized. - LESSONS.md: record the round.
- shared/Optics (Scala + Haskell) gains a Plated class/instance with descend + everywhere; example 2 declares its Plated[Expr] instance and lets everywhere do the walk instead of a hand-written recursion. - Motivation: the smell is multiple long methods doing too much, with reach-the-value complexity mixed into the change code. - Page example-2 prose updated to say the walk comes from Plated (eo's visit-across-whole-trees recipe).
Generalize the Plated lesson from 'don't hand-write the recursion' to 'never hand-write intermediate helper methods in an example' (like the hand-defined everywhere). Folded into SKILL.md §3 and brief.md — the helper belongs in shared/ or a library; the example declares only the instance (which fields recurse).
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Refactoring 2 of 35 — Replace mutable fields with lenses (with its dual, inline the lens)
Second entry of the catalogue at
/refactorings/replace-mutable-fields-with-lenses/. Reworked in response to review: the entry now teaches optics (lens · prism · traversal) and the separation of how to reach a field from what to do with it, with correctness "lawful by construction" and law-solvers covered in Verification.Page
.andThenshape, composing smaller portable optics).cats-eo-laws,monocle-law,genvalidity-hspec-optics).Examples (rebuilt around eo's "navigate structures" recipes, self-contained optics in Scala + Haskell)
prism .andThen lens: upper the name of one Var node; misses pass through.varNameoptic at every tree node via bottom-upeverywhere.each .andThen prism .andThen lens(eo cookbook "visit through arbitrary structure"): bump only the successes of a batch.Verification
all properties passed— 12 properties (6 per language, equivalence + purpose).