59 lines
1.4 KiB
Markdown
59 lines
1.4 KiB
Markdown
|
|
# Haskell NonEmpty Waves
|
||
|
|
|
||
|
|
This note covers `32-haskell-nonempty-waves/`, which models rollout plans with `NonEmpty` so every plan is guaranteed to have at least one wave.
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 1. Why `NonEmpty` Matters
|
||
|
|
|
||
|
|
A rollout plan with zero waves is not meaningful.
|
||
|
|
|
||
|
|
Using `[Wave]` would force every caller to handle an impossible-but-representable empty case. This example makes that impossible state unrepresentable
|
||
|
|
instead:
|
||
|
|
|
||
|
|
```haskell
|
||
|
|
planWaves :: NonEmpty Wave
|
||
|
|
```
|
||
|
|
|
||
|
|
That means the rendering code can safely ask for the first and last wave without defensive checks.
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 2. What the Example Builds
|
||
|
|
|
||
|
|
The example turns a release job into:
|
||
|
|
|
||
|
|
- one wave for a rolling rollout, or
|
||
|
|
- two waves for a canary rollout.
|
||
|
|
|
||
|
|
Both cases still share the same output type. That is the real teaching point: `NonEmpty` lets you preserve list-like behavior while tightening the
|
||
|
|
domain guarantee.
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 3. Why This Is Better Than a Runtime Check
|
||
|
|
|
||
|
|
You could build a plain list and reject `[]` later.
|
||
|
|
|
||
|
|
That would move the invariant into comments and runtime branches. `NonEmpty` pushes the guarantee into the type itself, which is more precise and
|
||
|
|
easier to trust.
|
||
|
|
|
||
|
|
---
|
||
|
|
|
||
|
|
## 4. Commands to Try
|
||
|
|
|
||
|
|
```bash
|
||
|
|
cd 32-haskell-nonempty-waves
|
||
|
|
|
||
|
|
nix develop
|
||
|
|
cabal run
|
||
|
|
cabal run -- api:production:canary:20:6
|
||
|
|
cabal test
|
||
|
|
|
||
|
|
nix build
|
||
|
|
./result/bin/mini-waves api:production:canary:20:6
|
||
|
|
|
||
|
|
nix run . -- api:production:canary:20:6
|
||
|
|
nix flake check
|
||
|
|
```
|