The Simply Typed Lambda Calculus
Abstract
This post is part of a series on how to reason about code. It describes the Simply Typed Lambda Calculus, a precursor to the formal language understood by Coq, an interactive proof assistant I am learning. More background can be found here, and the post that describes the λ Calculus itself can be found here.
This exposition follows closely that in "Type Theory & Formal Proof" by Nederpelt & Geuvers (abbreviated TTFP throughout).
Recap
In the last post, we saw that the λ Calculus is way to make precise the notion of computatation (see here for a capsule history as to why we would want to do this). As such, it should not be surprising that it is a very expressive formalism. It is Turing-complete, and in particular it allows us to write programs that never terminate. We saw the self-application function in the last post, but here's another example, once again from TTFP: let Δ be the term
In order to rule out such pathological terms, Church in his 1940 paper "A Formulation of the Simple Theory of Types" added a type system to the λ Calculus. We call the language that results from only permitting "well-typed" λ-terms the Simply Typed Lambda Calculus, or
Recall the Untyped λ Calculus: we started with a set of variables
- naming :: if
, then is a term (in the λ Calculus) - abstraction :: if
is a term & , then is a term, where may (or may not) occur in - application :: if
and are terms, then is a term
giving us an infinite set of λ-terms like
Call the elements of
- if
, then - if
, then
So bool
, for instance), and the arrow suggests mapping; a term with type
In
The types of applications & abstractions are built from those of their constituents. In the case of abstraction, if
Analogously, the application
At this point in our development of
We formalize this by defining the set of pre-typed λ-terms
This is just the set of all terms we can possibly write according to our rules so far. Whether these terms belong in
A pre-typed λ-term
Derivations
I've used the phrase "can be shown", above. Let's make that precise.
We can validate a judgement
Each rule tells us what we can conclude so long as we know certain things already. In the case of (3) & (4), the premises are written above the line & the conclusions below. In the case of (2), there are no premises: if
Let's work through an example (this is exercise 2.10 (d) in TTFP). Consider the term
So we see that if we assume
Figure 1:
We see that each leaf of this tree is an application of the (var) rule. Beginning in the upper right-hand corner, we've applied (var) twice to conclude that
To the left, we state that
The reader may note a few things from this example. Firstly, derivations can quickly become large & complex. This is a fairly short judgement and it's already spread over the width of the page. Secondly, they entail repetition. In this judgement, we need to introduce
Nederpelt & Geuvers introduce an alternative format for derivations that they call "flag format". They suggest that this is their invention, but don't quite say it, so I'm not sure where it originated. Here, we surround each type declaration with a box (a "flag") and mark the extent of that declaration's context by drawing a line below it (the "flag pole"); all steps to the right of the flag pole assume that declaration in their context. The flag notation for the above derivation is:
Figure 2:
We see that this style contains the same information as Figure 1: three invocations of (appl) & one of (abst). We have, however, omitted the applications of the (var) rule in the service of compactness & readability.
Note also that the flag pole corresponding to
Questions We Can Ask
We are interested in three different problems pertaining to judgements in Type Theory:
- Well-typedness/Typability
- Consider
(or ); given a term, is it legal in some context (or, is it legal in the given context)? - Type checking
- Consider
; given a judgement, is it true? - Term finding
- Consider
; is there a term of the given type in the given context?
Typability
In this case, we are handed a term, perhaps along with a context, and we need to find a derivation. Conceptually, we begin with the desired conclusion & attempt to work backwards. Continuing with our example
Figure 3: Typing step 1
We now have, on line (2), an application whose right-hand side is the variable
Figure 4: Typing step 2
We see we'll again need to apply (appl), this time requiring a declaration of the type of
Figure 5: Typing step 3
We see that the only feasible type for
Figure 6: Typing step 4
Since
Hence, we determine that
Figure 7: Typing step 5
As an example of a term that is not typable, consider
Type Checking
To continue our running example, validating that
Figure 8: Type-checking in
This is left as an exercise for the reader.
Term Finding
If I perhaps skimmed the last section, it was in my hurry to get to term finding. You see, in
For now, let's consider the problem of finding a term that inhabits type
Figure 9:
But at this point, we just need some term of type γ. Now, we could just give ourselves one, at the cost of "injecting" it into our context. That is, we could do this:
Figure 10:
This derivation only justifies the judgement
Figure 11:
…and we now need to cast around for a term of type γ within these assumptions. We notice that
Figure 12:
Now we need something of type β, and we see immediately that
Figure 13:
We see that, so long as we want to keep our context, we wound-up with the same derivation given above, but there may well be other terms inabiting any given type. The interesting question is whether the differences in terms inhabiting a type are interesting to us or not, but again, we'll come to that later in our story.
Where Are We?
We've refined our formal model for computation with the addition of types in order to rule-out misbehaving terms. We've also laid out the idea of derivation rules & their application in order to validate judgements regarding type. As we'll see, different derivation rules give rise to different type systems. In
And Church succeeded in his aim: every legal term in
Originally published 05/20/24 06:55. Updated 05/21/2024 to build-out the section on term finding to re-use the same context (which is much more interesting).