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
datatype 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)[g. type_of (M ..) T] → [g. step (M ..) (N ..)]
→ [g. type_of (N ..) T] =
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)[g. type_of (M ..) T] → [g. step (M ..) (N ..)] → [g. type_of (N ..) T] =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