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

2.2 KiB

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:

validateManifest :: RawManifest -> Validation [String] ReleaseManifest

It builds the final manifest with applicative style:

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

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