◄ WORLD V · SONNY 5DART 253 · a helldive at the net

THE REFINEMENT TYPE a type plus a predicate: {x : Int | x > 0}

A refinement type attaches a logical predicate to a base type: {x : Int | x > 0} is the positives, {a : Array | len a > 0} is the non-empty arrays. The type checker discharges the predicates — often to an SMT solver — so head can require a non-empty list and a caller who cannot prove it gets a type error. Refinement types are a sweet spot: far more expressive than plain types, far more automatable than full dependent types. They let you state and enforce “this is always in range” without writing a proof by hand.

THE TECHNIQUE base type + predicate; the checker discharges the refinement

The refinement {x | x > 0} over a sample array. The demo counts how many values inhabit the refined type: live demo


HISTORY & CREDIT Constable · Freeman-Pfenning · Liquid

“Int is Int; ranges are a runtime concern.” — a refinement makes “positive” part of the type, so the check happens once, at compile time, and every use downstream is free. The predicate rides in the type instead of littering the code with guards. cited

1980s · Robert Constable (Nuprl) — subset types {x:A | B}: a type refined by a proposition — the predicate form shown here.
1991 · Tim Freeman & Frank Pfenning — coin refinement types for ML: datasort (constructor) refinements, intersection-type based.
2008 · Rondon, Kawaguchi & JhalaLiquid Types: predicate refinements inferred and SMT-discharged.
now · LiquidHaskell, F*, Dafny — lightweight verification in the type checker.

A refinement is a proof obligation the type carries: state x > 0 and the solver must discharge it at every use. Verification becomes typechecking — without hand-written proofs. Constable · Liquid Types

RECOMMEND FOR I-13 inhabitants of the refinement, computed

On the canonical compiler, over [5, -2, 3, 0, 7] the refinement {x | x > 0} has 3 inhabitants (5, 3, 7):

$ i13 run t_refinement.i13 # count x where x > 0 satisfying = 3 -- 5, 3, 7 inhabit {x | x > 0}
Recommend: refinement types are the most plausible thing i13 could actually adopt — a lightweight annotation, not a whole type system. i13's validator already proves per-region facts and already runtime-checks ranges (E0501); a refinement like {i | 0 ≤ i < len} is precisely the predicate that would let it discharge a bounds check statically (dart 241 again). Refinements are dependent types' pragmatic cousin, and they sit closest to i13's grain: prove a predicate once, keep the guarantee, drop the runtime cost — correctness-first, single-obligation, no proof by hand.