A topic in the Open Knowledge Graph — a free, open map of 15,290 topics and the order to learn them in.

Refinement Types

Research Depth 95 in the knowledge graph I know this Set as goal
1topic build on this
514prerequisites beneath it
See this on the map →
Type Systems OverviewDependent Type Theory+1 moreLiquid Types
liquid-types liquid-haskell smt predicate-refinement subtyping

Core Idea

Refinement types augment base types with logical predicates that constrain the set of values. Instead of just Int, you write {v : Int | v > 0} — the type of positive integers. A function div : Int -> {v : Int | v != 0} -> Int statically guarantees the divisor is nonzero. Unlike full dependent types, refinement predicates are restricted to decidable logics (typically quantifier-free theories handled by SMT solvers), enabling fully automatic type checking without manual proofs. Liquid types, the most successful refinement type system, infer refinement predicates automatically using abstract interpretation over types, combining the expressiveness of dependent-types-lite with the automation of type inference.

Explainer

Full dependent types (as in Coq or Agda) let types express arbitrarily precise specifications, but at a cost: type checking is undecidable and requires the programmer to construct proofs manually. At the other extreme, simple type systems (as in Java or Python) are fully automatic but cannot express properties like "this integer is positive" or "this list is sorted." Refinement types occupy a sweet spot: they extend base types with logical predicates, gaining significant expressive power while retaining automatic type checking.

A refinement type has the form {v : T | P(v)}, where T is a base type and P is a logical predicate. The type {v : Int | v > 0} contains exactly the positive integers. A function can declare `div : (x : Int) -> (y : {v : Int | v != 0}) -> Int`, making division by zero a static type error. Array access can use `get : (a : Array T) -> (i : {v : Int | 0 <= v && v < len(a)}) -> T`, making out-of-bounds access a type error. These specifications live in the type system, are checked at compile time, and carry zero runtime cost.

The key to automation is restricting predicates to decidable theories that SMT solvers can handle. Liquid types, developed by Rondon, Kawaguchi, and Jhala, restrict refinements to conjunctions of qualifiers — simple predicates from a fixed set — and use abstract interpretation to infer which qualifiers apply at each program point. Subtype checking reduces to SMT validity: {v : T | P} is a subtype of {v : T | Q} if and only if P implies Q, which the solver decides automatically. LiquidHaskell applies this to Haskell, enabling programmers to verify memory safety, termination, functional correctness, and information flow properties with minimal annotation burden. The tool infers most refinements automatically; the programmer adds annotations only where inference needs guidance.

Path sensitivity is crucial for practical refinement typing. Inside `if x > 0 then f(x) else g(x)`, the type of x in the then-branch is refined to {v : Int | v > 0} by the branch condition. The type checker tracks these path conditions and includes them in SMT queries. This means that idiomatic null checks, bounds checks, and error handling are automatically recognized by the type system. The programmer does not need to add explicit annotations for code that already checks its preconditions — the type system extracts the information from the control flow.

Refinement types are less expressive than full dependent types — they cannot express properties requiring quantifiers (like "for all elements in this list, P holds") without extensions. But for a large class of safety and correctness properties — array bounds, division by zero, resource protocol compliance, numeric invariants — they provide strong static guarantees with an experience closer to ordinary type checking than to theorem proving. Tools like LiquidHaskell, Flux (for Rust), and F* (which combines refinement and dependent types) demonstrate that refinement types can scale to substantial codebases while catching real bugs that conventional type systems miss.

Practice Questions 3 questions

Prerequisite Chain

Understanding ZeroThe Number ZeroCounting to FiveCounting to 10Counting to 20Counting a Set of Objects Up to 20Cardinality: The Last Number CountedMatching Numerals to QuantitiesSubitizing Small QuantitiesAddition Within 10Number Bonds to 10Addition Within 20Doubles and Near DoublesDoubles Facts Within 10Near Doubles Facts Within 20Mental Math Strategies for AdditionMental Math: Adding and Subtracting TensAddition Within 100Repeated Addition as MultiplicationMultiplication as Equal GroupsMultiplication: ArraysBasic Multiplication Facts (0s, 1s, 2s, 5s, 10s)Multiplication Facts Within 100Division as Equal SharingDivision as Grouping (Measurement Division)Division: Grouping (Repeated Subtraction) ModelDivision: Fair Sharing ModelDivision as Equal SharingDivision as GroupingBasic Division FactsDivision Facts Within 100Multiplication and Division Fact FamiliesRelationship Between Multiplication and DivisionDivision Facts as Inverse of MultiplicationRemainders and Quotients in DivisionDivision Word ProblemsMulti-Step Word ProblemsSolving Multi-Step Word ProblemsMultiplication Word ProblemsDivision Word ProblemsIntroduction to Long DivisionFactors and MultiplesPrime and Composite NumbersEquivalent FractionsRelating Fractions and DecimalsDecimal Place ValueIntegers and the Number LineComparing and Ordering IntegersAbsolute ValueAdding IntegersSubtracting IntegersMultiplying IntegersIntroduction to ExponentsOrder of OperationsInteger Order of OperationsVariable ExpressionsThe Distributive PropertyVariables and Expressions ReviewIntroduction to PolynomialsAdding and Subtracting PolynomialsMultiplying PolynomialsFactorialPermutationsCombinationsCounting Principles: Addition and Multiplication RulesIntroduction to Graph TheoryPropositional Logic FoundationsLogical EquivalencesBoolean AlgebraBoolean Type and Truth ValuesComparison Operators and Boolean TestsLogical Operators and Boolean AlgebraBoolean Algebra and Fundamental LawsLogic Gates FundamentalsImplementing Boolean Functions with GatesKarnaugh Map SimplificationCombinational Circuit DesignFlip-Flops and LatchesFinite State Machines (FSMs)Deterministic Finite Automata (DFA)Nondeterministic Finite Automata (NFA)Two-Way Finite AutomataNFA to DFA Conversion (Subset Construction)DFA Properties and Minimization AlgorithmsRegular Languages: Definition and CharacterizationContext-Free Grammars (CFGs)Context-Free Grammar Properties and AmbiguityParse Trees, Derivations, and Ambiguity in CFGsContext-Free Grammars in Compiler DesignAbstract Syntax Trees (ASTs)Symbol Tables and Scope ResolutionSemantic Analysis PhaseType Systems OverviewCurry-Howard CorrespondenceDependent Type TheoryRefinement Types

Longest path: 96 steps · 514 total prerequisite topics

Prerequisites (3)

Leads To (1)