Tutorial
Proofs about the simply-typed lambda-calculus
1. Type uniqueness
2. Reasoning about paths in lambda-terms
3. Subject reduction
We explain here how to implement the subject reduction proof for the simply-typed lambda-calculus. If you'd like to run this example using Beluga, please download subject-red.bel, which contains all the data-type definitions and the implementation of the proof as a recursive function.
We first define a big step semantics for the simply-typed lambda-calculus using the familiar LF methodology. We define first the type family
notLam: exp → type.
n_app: notLam (app M N).
step: exp → exp → type.
s_lam: ({x:exp}step x x → notLam x → step (M x) (N x))
→ step (lam T M) (lam T N).
s_app1: step (M' N) R → step M (lam T M')
→ step (app M N) R.
s_app2: step N N' → notLam M' → step M M'
→ step (app M N) (app M' N').
To implement the subject reduction theorem, we typically state it as follows:
Theorem (Attempt 1): If Γ ⊢
We note however that the context Γ and the context Ψ are different; for the proof to go through we need some relationship between the typing assumptions in the context Γ and the assumptions
We therefore define first a context Φ which contains both these assumptions.
| Φ | ::= | . | Φ, type_of x T, step x x, notLam x |
We now restate the subject reduction theorem with the generalized context Φ.
Theorem: If Φ ⊢
In Beluga, we specify the structure of the context using context schema as follows:
schema ctx = some [t:tp] block x:exp,u:type_of x t, v:step x x . notLam x;
It specifies that the context of schema
The theorem is represented as a computation-level type in Beluga:
{g:ctx}(type_of (M ..) T)[g] → (step (M ..) (N ..))[g]
→ (type_of (N ..) T)[g] =
Quantification over the context variable
The proof of the subject reduction theorem is then implemented as a recursive program. Case analysis and inversion in the informal proof are modelled via case analysis and let-expressions in the Beluga implementation. Appeals to the induction hypothesis correspond to recursive calls.
rec tps: {g:ctx}(type_of (M ..) T)[g] → (step (M ..) (N ..))[g] → (type_of (N ..) T)[g] =fn d ⇒fn s ⇒case sof | [g] s_lam \x.\v. \n. S .. x v n ⇒let [g] t_lam \x.\u. D .. x u = din let [g, b: block x:exp, u:type_of x T, v:step x x. notLam x] F .. b.1 b.2 = tps ([g,b:block x:exp,u:type_of x _ ,v:step x x. notLam x] D .. b.1 b.2) ([g,b] S .. b.1 b.3 b.4)in [g] t_lam \x.\u. F .. x u | [g] s_app1 (S2 ..) (S1 ..) ⇒let [g] t_app (D2 ..) (D1 ..) = din let [g] t_lam \x.\u. F .. x u = tps ([g] D1 ..) ([g] S1 ..)in tps ([g] F .. _ (D2 ..)) ([g] S2 ..) | [g] s_app2 (S2 ..) _ (S1 ..) ⇒let [g] t_app (D2 ..) (D1 ..) = din let [g] F1 .. = tps ([g] D1 ..) ([g] S1 ..)in let [g] F2 .. = tps ([g] D2 ..) ([g] S2 ..)in [g] t_app (F2 ..) (F1 ..) | [g] #p.3 .. ⇒ % s : step (#p.1 ..) (N ..)let [g] #q.2 .. = din % q : block x:exp,u:type_of x t, v:step x x . notLam x % since step #q.1 #q.1 = step #p.1 (N ..) % N = #q.1 and #q = #p [g] #q.2 .. ;
The implementation of the proof mirrors closely the on-paper proof.
4. Equality reasoning
5. Reasoning about smaller relation on lambda-terms