The word simple types is also used to refer to extensions of the simply typed lambda calculus such as products, coproducts or natural numbers (System T) or even full recursion (like PCF). In contrast, systems which introduce polymorphic types (like System F) or dependent types (like the Logical Framework) are not considered simply typed. The former are still considered simple because the Church encodings of such structures can be done using only and suitable type variables, while polymorphism and dependency cannot.
The syntax of the simply typed lambda calculus is essentially that of the lambda calculus itself. The term syntax used in this article is as follows:
That is, variable reference, abstractions, and application. A variable reference is bound if it is inside of an abstraction binding . A term is closed if there are no unbound variables.
It is possible to define the syntax as in the untyped lambda calculus, with unannotated abstractions. Since type inference or reconstruction is tractable for the simply typed lambda calculus, the decision doesn't matter from a "typeability" perspective. The type system for the annotated version, however, has an algorithmic interpretation, while the algorithm for type-checking unannotated and partially annotated terms is more complex. For more information, see the article on Algorithm W.
The syntax of types is:
We take and to be type variables drawn from a predetermined set, while we reserve and as metavariables, meaning "some type". The function type refers to the set of functions that, given an input of type , produce an output of type .
By convention, associates to the right: we read as .
Each type is assigned an order, a number . For base types, ; for function types, . That is, the order of a type measures the depth of the most left-nested arrow.
There are two distinct presentations of simply typed lambda calculus. In Curry-style semantics, the operational semantics comes first, and the static semantics (typing rules) comes second. In Church-style semantics, the static semantics is given first; the operational semantics apply only to terms that are accepted by the static semantics.
Note that this distinction is not precisely the same as that between unannotated and annotated abstractions. It is possible to give a Curry-style semantics using annotated lambdas: the operational semantics simply ignore types altogether.
Beyond these distinctions, there are then further variations based on calling conventions and evaluation strategy (call by name, call by value, etc.) and presentation (big-step, small-step, etc.).
To define the set of well typed lambda terms of a given type, we will define a typing relation between terms and types. First, we introduce typing contexts, which are sets of typing assumptions. A typing assumption has the form , meaning has type .
The typing relation indicates that is a term of type in context . It is therefore said that " is well-typed (at )". A typing judgment is constructed via of the following rules, wherein the premises above the line allow us to derive the conclusion below the line:
| (1) |
| (2) |
| (3) |
In other words,
One can construe these judgments not merely as relations between terms and types, but as the construction of terms themselves. This coincides with Church-style semantics, as it is then only possible to construct well-typed terms.
Examples of closed terms, i.e. terms typable in the empty context, are:
These are the typed lambda calculus representations of the basic combinators of combinatory logic.
In the original presentation, Church used only two base types: for the type of propositions and for the type of individuals. Frequently the calculus with only one base type, usually , is considered.
Terms of the same type are identified via -equivalence, which is generated by the equations , where stands for with all free occurrences of replaced by , and , if does not appear free in . The simply typed lambda calculus (with -equivalence) is the internal language of Cartesian Closed Categories (CCCs), this was first observed by Lambek.
In the unannotated syntax, lambda abstractions carry no type information. As a consequence, terms can have more than one type. If we consider the type variables to be implicitly universally quantified, then it is possible to find a type more general than the others, called the principal type.
For example, the identity function can have many types: , say, or , and so on. Without quantifiers in our type language (as in System F), it is impossible to say what type "really" has. Extensions of simply typed lambda calculus can add support for polymorphism: terms that can have multiple types. System F, for example, adds general abstractions over types: takes a type and returns the identity function at that type. The term has type .
If one considers the unannotated lambda calculus extended with constants, such as integers, booleans, and tuples, the problem of typing becomes easier: might be easily determined to have type . The problem above does not go away entirely, though: what type does have? There are an infinite number (, , etc.). The principal type of the term is .
The simply typed lambda calculus is closely related to propositional intuitionistic logic using only implication () as a connective (minimal logic) via the Curry-Howard isomorphism: the types inhabited by closed terms are precisely the tautologies of minimal logic.
Given the standard semantics, the simply typed lambda calculus is strongly normalizing: that is, well-typed terms always reduce to a value, i.e., a abstraction. This is because recursion is not allowed by the typing rules: it is impossible to find types for fixed-point combinators and the looping term . Recursion can be added to the language by either having a special operator of type or adding general recursive types, though both eliminate strong normalization.
Since it is strongly normalizing, it is decidable whether or not a simply typed lambda calculus program halts: it does! We can therefore conclude that the language is not Turing complete, which has an undecidable halting problem.