System F
System F, also known as the polymorphic lambda calculus or the second-order lambda calculus, is the simplest type system that supports parametric polymorphism — the ability to abstract functions not just over values but over types. Discovered independently by the logician Jean-Yves Girard and the computer scientist John C. Reynolds in the early 1970s, it is the type-theoretic core of modern functional programming languages and the direct ancestor of the polymorphic type systems of ML, Haskell, and the impredicative universe of the Coq proof assistant.
System F extends the simply typed lambda calculus with universal quantification over types: a term can have the type ∀α.α → α, meaning it is a function that works for any type α. This is not generics in the object-oriented sense — it is a foundational principle that the behavior of a polymorphic function is determined entirely by its type, a property known as parametricity that Reynolds formalized as the abstraction theorem. The expressive power of System F is remarkable: it can encode natural numbers, booleans, lists, and trees as pure lambda terms, without any primitive data types. Yet this power comes with a cost: type inference for System F is undecidable, which is why real programming languages restrict polymorphism to let-bound expressions.
The Path to Dependent Types
System F is the summit of the simply-typed hierarchy, but it is also a dead end in one crucial respect: its types cannot depend on terms. In System F, the type "list of natural numbers" and the type "list of length n" are fundamentally different species of object — the first is a type, the second is a type family indexed by a value. The inability of types to speak about values means that System F can encode data structures but not their specifications. It can express a sorting function, but not the proposition that the output is sorted. It can express a list, but not the invariant that its length is preserved by map.
The Calculus of Constructions resolves this by adding dependent types — the ability of types to be indexed by terms, and of terms to appear in types. This single extension transforms System F from a programming language into a logic. The universal quantification of System F (\u2200\u03b1.\u03c4) becomes, in the CoC, a dependent product (\u2200x:A.B) where the quantification is over values as well as types. The difference is not syntactic sugar; it is the difference between a system that can talk about programs and a system that can talk about what programs mean.
The historical trajectory is instructive. System F was discovered in the 1970s as a solution to the problem of polymorphism. The Calculus of Constructions was discovered in the 1980s as a solution to the problem of specification. The first asked: how can we write one program that works for many types? The second asked: how can we write one type that describes many programs? The questions are dual, and the answers are the same system with one additional rule. The path from System F to the CoC is therefore not a historical accident but a logical necessity: any type theory rich enough to express polymorphism will, if pushed slightly further, express dependent types, and any system with dependent types is a logic waiting to be recognized as such.
System F is often treated as a historical waypoint — the polymorphic ancestor of ML and Haskell, respectable but surpassed. This is a mistake. System F is the proof that polymorphism is not a compiler convenience but a logical principle, and the undecidability of its type inference is not a flaw but a theorem about the limits of automation. The persistence of System F as a theoretical object, despite its impracticality for full type inference, is evidence that type theory is not a branch of software engineering. It is a branch of logic, and its theorems do not care whether they are convenient.