Definition
A type-theoretic feature and family of systems in which types may depend on values (terms), enabling types to express precise specifications, relate data and proofs, and internalize propositions as types.
Principle
Principle
Types-as-predicates: a type can be parameterized by a value (e.g., Vector n A) so that typing enforces value-level invariants; the correspondence between propositions and types (Curry–Howard) is realized at greater expressiveness.
Demonstration
Demonstration
Defining a type of lists with length n as List A n and writing a function append : ∀n m. List A n → List A m → List A (n + m); the type ensures at compile time that the result's length equals the sum of input lengths.
Misapplication
Misapplication
Encoding undecidable or heavyweight properties directly in types (e.g., using arbitrary search in typechecking) without care, which can make type checking nonterminating or programs impractical to write and maintain.
Consequence
Consequence
Allows embedding rich specifications in types so that many correctness properties are checked by the type checker, enabling program extraction from constructive proofs and high-assurance software when well-engineered.
Reversal
Reversal
Simple type systems where types are independent of runtime values (e.g., simply typed systems), which forgo expressive specifications in favor of decidable and efficient type checking.
Boundary
Boundary
Applies where the type-checking discipline supports value-level computation and termination checks; dependent types do not magically decide arbitrary semantic properties and often require totality/termination constraints and proof obligations.
Semantic Tension
Semantic Tension
Tension between expressive dependent types that can state strong invariants and the desire for decidable, efficient type checking and automation; also between using dependent types for proofs versus pragmatic programming ergonomics.
Synthesis
Synthesis
Dependent types extend the type system so that types can talk about values, turning types into precise specifications and enabling proofs about program behavior to live alongside code; they trade added expressiveness and verification power against increased complexity in type checking and development.