Object-oriented developers have a shared vocabulary for reshaping code without changing what it does — Fowler’s catalogue, Opdyke’s thesis, the Refactoring menu in every IDE — as well as a history of doing so informally before then. This is the same idea seen through the functional-programming imagination: each move takes a program from one structure to an equivalent one, and in a referentially transparent setting equivalent is something you can state and check.

Every entry that has a page shows the refactoring in Scala 3 and in Haskell, in both directions (the move and its inverse), with the papers and study material behind it, a diagram of the structural change, and a property-based test — Hedgehog in Scala and Hedgehog in Haskell — that exercises the before and after on generated inputs and demands the same answer. Entries without a link are queued; they will be filled in the order listed.

Refactorings

  1. Extract / Inline method
  2. Replace mutable fields with lenses
  3. Replace global state with parameter
  4. Introduce ReaderT (Kleisli)
  5. Replace loop with fold
  6. Replace recursion with fold
  7. Replace inheritance with natural transformation
  8. Replace exception with extended response type
  9. Replace null with optional
  10. Replace optional fields with sum types
  11. Replace sum types with optional fields
  12. Replace parameter with reduced type
  13. Replace mutable variable with recursion
  14. Replace similar methods with generic cousin
  15. Extract constant
  16. Merge into module
  17. Extract generic algebra
  18. Wrap side effect
  19. Pull out effect
  20. Lazy lists to eager arrows
  21. Replace unit tests with property-based test

With higher-kinded types

  1. Generalize over input constraint
  2. Isolate business key via data parametrization
  3. Remove recursion from GADT
  4. Replace visitor with type class
  5. Replace concrete classes with final tagless interpretation
  6. Replace final tagless with free monad
  7. Replace free monad with final tagless encoding
  8. Replace strategy with tagless final
  9. Replace subtypes with type class instances
  10. Replace pattern matching with type class dispatch
  11. Introduce higher-kinded constraint

With dependent types

  1. Introduce parameter-value-dependent constraint
  2. Introduce (path-)dependent type
  3. Replace (path-)dependent type with type class constraint