Tutorial
Proofs about the simply-typed lambda-calculus
1. Type uniqueness
2. Reasoning about paths in lambda-terms
This example illustrates the expressive power of Beluga. In particular, the theorem we discuss here requires nested impliciations and quantification, in particular negative occurrences of these connectives. For a much simpler theorem, also illustrating the need for handling negative occurrences of implications and quantifiers, see example 5. Reasoning about smaller relation on lambda-terms.
If you'd like to run this example using Beluga, please download path.bel, which contains all the type definitions and the implementation of the proof as a recursive function.
We interpret lambda-terms essentially as a tree-structure and paths describe how to traverse it. We begin by defining paths to describe a path through a given lambda-term.
datatype path :type = | bind : tp → (path → path) → path | left : path → path | right : path → path | done : path ;%name path P.
We can either go
Next, we define the inference rules for the traversal of a lambda-term.
datatype is_path : path → exp →type = | p_lam: is_path (bind T P) (lam T E) ← ({x:exp}{q:path}is_path q x → is_path (P q) (E x)) | p_left: is_path (left P) (app M N) ← is_path P M | p_right: is_path (right P) (app M N) ← is_path P N | p_done: is_path done M ; %name is_path I.
We want to prove the following theorem:
Theorem:For all
Since during the proof we will introduce assumptions about variables and the context will not remain empty, we will prove a more general version of the theorem first, and then derive the theorem as a corollary. The generalized version is next:
Lemma:For all
The statement of the lemma and theorem are good examples to illustrate the expressive power of Beluga. Because the statements require nested quantification and implication, it is not possible to state these theorems directly in some systems for example the Twelf system.
The context Γ contains assumptions
schema ctx = block x:exp, p:path . is_path p x ;
Formally, we are using a dependent product type or Σ-type to define the schema. So our concrete syntax of
On paper proof:
The proof for the stated lemma can be implemented as a recursive function
{g:ctx}{M:[g. exp]}{N:[g. exp]}
({P:[g. path]} [g. is_path (P ..) (M ..)] → [g. is_path (P ..) (N ..)])
→ [g. eq (M ..) (N ..)]
The type corresponds directly to the specified lemma where
The overall type can be read as follows: For all contexts
We first show one case of the proof how it is written on paper.
Case:
| 1 | for all |
||
| by assumption | |||
| 2 | |||
|
|
using |
||
| 3 | |||
| by rule |
|||
| 4 | by rule |
||
| 5 | using line 2 and line 4 | ||
| 6 | |||
| where |
using rule |
||
| 7 | |||
| using rule |
|||
| Let |
|||
| We need to establish: for all |
|||
| 8 | assume |
||
| Recall that assumption 1 is now: | |||
|
for all |
|||
|
|
|||
| 9 | |||
|
using |
|||
| 10 | |||
| using |
|||
| 11 | by inversion using |
||
| Hence, we have established a proof for: | |||
| for all |
|||
| 12 | by i.h. on |
||
| 10 | by rule |
||
| 11 | by rule |
||
The inductive proof can be implemented as a recursive function in Beluga following
closely the more informal development given earlier. We treat computation-level expressions
which correspond to quantifier introduction and elimination differently from the expressions
corresponding to implication introduction and elimination. To introduce a universally
quantified meta-variable
rec eqPath : {g:ctx}{M:[g. exp]}{N:[g. exp]} ({P:[g. path]} [g. is_path (P ..) (M ..)] → [g. is_path (P ..) (N ..)]) → (eq (M ..) (N ..))[g] =mlam g ⇒mlam M ⇒mlam N ⇒fn f ⇒case [g. M ..]of | [g. app (M1 ..) (M2 ..)] ⇒let [g. p_left p_done] : [g. is_path (left done) (app (N1 ..) (N2 ..))] = f [g. left done] [g. p_left p_done]in let [g. e_ref] = eqPath [g] [g. M2 ..] [g. N2 ..] (mlam Q ⇒fn iq ⇒let [g. D ..] = iqin let [g. p_right (D' ..)] : [g. is_path (right (Q' .. )) (app (N1 ..) (N2 ..))] = f [g. right (Q ..)] [g. p_right (D ..])in [g. D' ..]in let [g. e_ref] = eqPath [g] [g. M1 ..] [g. (N1 ..)] (mlam Q ⇒fn iq ⇒let [g. D ..] = iqin let [g. p_left (D' ..)] : [g. is_path (left (Q' .. )) (app (N1 ..) (N2 ..))] = f [g. left (Q ..)] [g. p_left (D .. )]in [g. D' ..] )in [g. e_ref] | [g. #p.1 ..] ⇒let [g. #q.3 ..] = f [g. #p.2 .. ] [g. #p.3 ..]in [g. e_ref] | [g. lam T (\x. M' .. x)] ⇒let [g. p_lam (\x.\p. \i. p_done)] : [g. is_path (bind T' (\p.done)) (lam _ (\x. N' .. x))] = f [g. bind T (\p.done)] [g. p_lam (\x.\p.\i. p_done)]in let [g,b:block x:exp, q:path . is_path q x. e_ref] = eqPath [g, b:block x:exp, q:path . is_path q x] [g,b. M' .. b.1] [g,b. N' .. b.1] (mlam Q ⇒fn ip ⇒let [g,b:block x:exp, q:path. is_path q x. Qs .. b.2] = [g,b:block x:exp, q:path. is_path q x. Q .. b]in % strengthening let [g,b:block x:exp, q:path. is_path q x. D .. b] = ipin let [g. p_lam (\x.\q.\iq. D' .. x q iq)] : [g. is_path (bind _ (\q. Q' .. q)) (lam _ (\x. N' .. x))] = f [g. bind T (\q. Qs .. q)] [g. p_lam (\x.\q.\iq. D .. x,q,iq) ]in [g,b. D' .. b.1 b.2 b.3] )in [g. e_ref] ;rec path_thm : {M:[ . exp]}{N:[ . exp]} ({P:[ . path ]}([ . is_path P M] → [ . is_path P N]) → [ . eq M N] =mlam M ⇒mlam N ⇒fn f ⇒ eqPath [ ] [ . M] [ . N] f ;
3. Subject reduction
4. Equality reasoning
5. Reasoning about smaller relation on lambda-terms