nix-playgraound/notes/031-haskell-applicative-validation.md

80 lines
2.2 KiB
Markdown

# Haskell Applicative Validation
This note covers `28-haskell-applicative-validation/`, which validates a release manifest with a custom `Validation` type that accumulates several
field errors at once.
---
## 1. Why This Is Not Just `Either`
`Either` stops at the first failure. That is useful for many workflows, but it is not always the best fit for validating a form-like input.
This example wants a different behavior:
- validate `service`,
- validate `env`,
- validate `owners`,
- validate `replicas`,
- validate `strategy`, and
- validate `window`,
and report every invalid field in one pass.
That is why the example uses a `Validation` type with an `Applicative` instance that combines errors through `Semigroup`.
---
## 2. Where the Accumulation Happens
The important function is:
```haskell
validateManifest :: RawManifest -> Validation [String] ReleaseManifest
```
It builds the final manifest with applicative style:
```haskell
ReleaseManifest
<$> validateService ...
<*> validateEnvironment ...
<*> validateOwners ...
<*> validateReplicas ...
<*> validateStrategy ...
<*> validateWindow ...
```
Each field validator can fail independently, and the `Applicative` instance combines all the resulting error lists.
---
## 3. Why the Input Is Split into Two Stages
The example still parses `key=value` assignments with `Either`.
That keeps syntax errors separate from semantic validation:
- malformed assignments such as `service` or `owners=` fail immediately, and
- well-shaped assignments become a `RawManifest` that the validation layer can inspect field by field.
This separation keeps the example focused. The interesting part is accumulated validation, not ad hoc string parsing.
---
## 4. Commands to Try
```bash
cd 28-haskell-applicative-validation
nix develop
cabal run
cabal run -- service=api-gateway env=production owners=platform,security replicas=3 strategy=canary:20 window=22-24
cabal test
nix build
./result/bin/mini-validation service=api-gateway env=production owners=platform,security replicas=3 strategy=canary:20 window=22-24
nix run . -- service=api-gateway env=production owners=platform,security replicas=3 strategy=canary:20 window=22-24
nix flake check
```