nix-playgraound/notes/027-haskell-deriving.md

65 lines
1.7 KiB
Markdown
Raw Normal View History

# Haskell Deriving Strategies
This note covers `24-haskell-deriving/`, which uses `deriving stock` and `GeneralizedNewtypeDeriving` to build useful behavior for release-planning
types with very little manual code.
---
## 1. What the Example Derives
The example derives three kinds of behavior:
- ordering and display for enums and records,
- enumeration for the environment list, and
- numeric and semigroup behavior for newtypes.
Those derived instances are then used directly in the program:
- `allEnvironments` comes from `Enum` and `Bounded`,
- `sortedTargets` relies on derived `Ord`, and
- `totalFailureBudget` relies on derived `Num`.
---
## 2. Why the Constructor Order Matters
Derived ordering is not magical. It follows constructor order for sum types, and field order for product types.
That matters in this example:
- `Priority` lists `Urgent` before `Standard` and `Background`, so urgent work sorts first, and
- `ReleaseTarget` stores environment and priority before the service name, so the derived record ordering matches the intended rollout order.
This is the main teaching point: derived instances are only as good as the domain shape you give them.
---
## 3. Why the Newtypes Are Useful
`BatchName` and `FailureBudget` are wrappers, but they still need behavior.
`GeneralizedNewtypeDeriving` lets the example reuse the underlying instances:
- `BatchName` derives `Semigroup` and `Monoid`, and
- `FailureBudget` derives `Num` and `Ord`.
That means the code can concatenate names and sum budgets without unpacking the wrappers everywhere.
---
## 4. Commands to Try
```bash
cd 24-haskell-deriving
nix develop
cabal run
cabal test
nix build
./result/bin/mini-deriving
nix run
nix flake check
```