diff --git a/examples/literate_beluga/0Beginner/Parallel_Reduction.bel b/examples/literate_beluga/0Beginner/Parallel_Reduction.bel index 1475c3a32..973e3df57 100755 --- a/examples/literate_beluga/0Beginner/Parallel_Reduction.bel +++ b/examples/literate_beluga/0Beginner/Parallel_Reduction.bel @@ -74,14 +74,14 @@ schema trCtx = some [t:tp] block x:tm, of_v: oft x t, pr_v: pr x x; %{{ ## Substitution Lemma Beluga enjoys the usual substitution property for parametric and hypothetical derivations for free since substitutivity is just a by-product of -hypothetical-parametric judgements. Strictly speaking, the substitution lemma does not need to be stated explicitly in order to prove type preservation for parallel reduction but we've encoded it regardless. While this is usually proved by induction on the first derivation, we show it as a corollary of the substitution principles.}}% +hypothetical-parametric judgements. Strictly speaking, the substitution lemma does not need to be stated explicitly in order to prove type preservation for parallel reduction but we've encoded it regardless. While this is usually proved by induction on the first derivation, we show it as a corollary of the substitution principles. In stating the substitution lemma we explicitly state that the types S and T cannot depend on the context g, i.e. they are closed.}}% rec subst : (g:tCtx) [g,b: block x:tm, of_v: oft x T[] |- oft M[..,b.1] S[]] -> [g |- oft N T[]] -> [g |- oft M[..,N] S[]] = fn d1 => fn d2 => let [g, b: block x:tm, of_v: oft x T |- D1[..,b.1,b.2]] = d1 in -let [g |- D2[..]] = d2 in +let [g |- D2] = d2 in [g |- D1[..,_,D2]] ; @@ -91,34 +91,34 @@ let [g |- D2[..]] = d2 in % Type preservation for parallel reduction %{{ ## Type Preservation for Parallel Reductions -We prove type preservation for parallel reduction: when M steps to N and M has type A then N has the same type A. expressions to depend on the context since we may step terms containing variables. Substitution property for parametric and hypothetical derivations is free. }}% +We prove type preservation for parallel reduction: when M steps to N and M has type A then N has the same type A. expressions to depend on the context since we may step terms containing variables. Substitution property for parametric and hypothetical derivations is free. We do not enforce here that the type A is closed. Although this is possible by writing A[] the statement looks simpler if we do not enforce this extra invariant.}}% rec tps : (g:trCtx) - [g |- pr (M[..]) (N[..])] -> [g |- oft (M[..]) A] - -> [g |- oft (N[..]) A] = + [g |- pr M N] -> [g |- oft M A] + -> [g |- oft N A] = fn r => fn d => case r of -| [g |- #p.3[..] ] => d -| [g |- pr_b (\x.\pr_v. R1) (R2[..] ) ] => - let [g |- of_app (of_lam (\x.\of_v. D1)) (D2[..]) ] = d in +| [g |- #p.3 ] => d +| [g |- pr_b (\x.\pr_v. R1) R2 ] => + let [g |- of_app (of_lam (\x.\of_v. D1)) D2 ] = d in let [g, b: block x:tm, of_v: oft x T, pr_v: pr x x |- F1[..,b.1,b.2]] = tps [g, b: block x:tm, of_v: oft x _, pr_v: pr x x |- R1[..,b.1,b.3]] [g, b |- D1[..,b.1,b.2]] in - let [g |- F2[..] ] = tps [g |- R2[..]] [g |- D2[..]] in + let [g |- F2 ] = tps [g |- R2] [g |- D2] in [g |- F1[..,_,F2]] % use substitution lemma directly -| [g |- pr_l \x.\pr_v. R] => +| [g |- pr_l \x.\pr_v. R] => let [g |- of_lam \x.\of_v. D] = d in let [g, b: block x:tm, of_v: oft x T, pr_v: pr x x |- F[..,b.1,b.2]] = tps [g, b: block x:tm, of_v: oft x _, pr_v: pr x x |- R[..,b.1,b.3]] [g, b |- D[..,b.1,b.2]] in [g |- of_lam \x.\of_v. F] -| [g |- pr_a (R1[..]) (R2[..]) ] => - let [g |- of_app (D1[..]) (D2[..])] = d in - let [g |- F1[..] ] = tps [g |- R1[..]] [g |- D1[..]] in - let [g |- F2[..] ] = tps [g |- R2[..]] [g |- D2[..]] in - [g |- of_app (F1[..]) (F2[..])] +| [g |- pr_a R1 R2 ] => + let [g |- of_app D1 D2] = d in + let [g |- F1] = tps [g |- R1] [g |- D1] in + let [g |- F2] = tps [g |- R2] [g |- D2] in + [g |- of_app F1 F2] ; %{{ -The β-reduction case is perhaps the most note-worthy. We know by assumption that d:[g |- oft (app (lam A (\x. M[..]x))(N[..])) (arr A B) and by inversion that d:[g |- of_a (of_l \x. \u. D1[..]x u)(D2[..]) ] where D1 stands for oft (M[..]x) B in the extended context g, x:tm , u:oft x A. Furthermore, D2 describes a derivation oft (N[..])A. A recursive call on D2 yields F2:oft (N'[..])A. Likewise, y the i.h. on D1, we obtain a derivation F1:oft (M'[..]x) B in g, b:block (x:tm , of_x:oft x A). We now want to substitute for x the term N', and for the derivation oft x A the derivation F2. This is achieved by applying to F1 the substitution .. _ (F2[..]). Since in the program above we do not have the name N available, we write an underscore and let Beluga's type reconstruction algorithm infer the appropriate name. +The β-reduction case is perhaps the most note-worthy. We know by assumption that d:[g |- oft (app (lam A (\x. M x)) N)) (arr A B) and by inversion that d:[g |- of_a (of_l \x. \u. D1 x u)(D2) ] where D1 stands for oft (M x) B in the extended context g, x:tm , u:oft x A. Furthermore, D2 describes a derivation oft N A. A recursive call on D2 yields F2:oft N' A. Likewise, y the i.h. on D1, we obtain a derivation F1:oft M' B in g, b:block (x:tm , of_x:oft x A). We now want to substitute for x the term N', and for the derivation oft x A the derivation F2. This is achieved by applying to F1 the substitution .., _ F2). Since in the program above we do not have the name N available, we write an underscore and let Beluga's type reconstruction algorithm infer the appropriate name. }}% diff --git a/examples/literate_beluga/0Beginner/Polymorphic_Algorithmic_Equality.bel b/examples/literate_beluga/0Beginner/Polymorphic_Algorithmic_Equality.bel index 6bbec4510..44b91bb9e 100755 --- a/examples/literate_beluga/0Beginner/Polymorphic_Algorithmic_Equality.bel +++ b/examples/literate_beluga/0Beginner/Polymorphic_Algorithmic_Equality.bel @@ -92,231 +92,229 @@ schema deqCtx = block x: term, u:aeq x x , _t:deq x x % ----------------------------------------------------------------- % % Admissibility of Reflexivity %{{## Proof of Reflexivity for Types -The reflexivity for types is implemented as a recursive function called reftp of type: {g:atpCtx}{T:[g |- tp ]}[g |- atp (T[..])(T[..])]. This can be read as: for all contexts g that have schema atpCtx, for all types T, we have a proof that [ g |- atp (T[..])(T[..])]. Quantification over contexts and contextual objects in computation-level types is denoted between braces {}; the corresponding abstraction on the level of expressions is written as mlam g => mlam T1 => e.}}% -rec reftp : {g:atpCtx} {T:[g |- tp]} [g |- atp (T[..]) (T[..])] = -mlam g => mlam T => case [g |- (T[..])] of -| [g |- #p.1[..]] => [g |- #p.2[..]] - -| [g |- all \x. T] => - let [g,b:block a:tp , _t:atp a a |- D[..,b.1,b.2]] = - reftp [g, b:block a:tp , _t:atp a a] [g, b |- T[..,b.1]] +The reflexivity for types is implemented as a recursive function called reftp of type: {gamma:atpCtx}{T:[gamma |- tp ]}[gamma |- atp T T]. This can be read as: for all contexts g that have schema atpCtx, for all types T, we have a proof that [ g |- atp T T]. Quantification over contexts and contextual objects in computation-level types is denoted between braces {}; the corresponding abstraction on the level of expressions is written as mlam g => mlam T1 => e.}}% +rec reftp : {gamma:atpCtx} {T:[gamma |- tp]} [gamma |- atp T T] = +mlam gamma => mlam T => case [gamma |- T] of +| [gamma |- #p.1] => [gamma |- #p.2] + +| [gamma |- all \x. T] => + let [gamma,b:block a:tp , _t:atp a a |- D[..,b.1,b.2]] = + reftp [gamma, b:block a:tp , _t:atp a a] [gamma, b |- T[..,b.1]] in - [g |- at_al \x. \w. D] + [gamma |- at_al \x. \w. D] -| [g |- arr (T[..]) (S[..])] => - let [g |- D1[..]] = reftp [g] [g |- T[..] ] in - let [g |- D2[..]] = reftp [g] [g |- S[..] ] in - [g |- at_arr (D1[..]) (D2[..])] +| [gamma |- arr T S] => + let [gamma |- D1] = reftp [gamma] [gamma |- T ] in + let [gamma |- D2] = reftp [gamma] [gamma |- S ] in + [gamma |- at_arr (D1) D2] ; -%{{In the proof for refltp we begin by introducing and T followed by a case analysis on [g |- T[..]] using pattern matching. There are three possible cases for T: +%{{In the proof for refltp we begin by introducing and T followed by a case analysis on [gamma |- T] using pattern matching. There are three possible cases for T: }}% %{{## Proof of Reflexivity for Terms -The recursive function ref encodes the proof reflexivity for terms. The type signature reads: for all contexts g that have schema aeqCtx, for all terms M, we have a proof that [ g |- aeq (M[..])(M[..])].}}% -rec ref : {g:aeqCtx} {M:[g |- term]} [g |- aeq (M[..]) (M[..])] = -mlam g => mlam M => case [g |- (M[..])] of -| [g |- #p.1[..]] => [g |- #p.2[..]] - -| [g |- lam \x. M] => - let [g,b:block y:term , _t:aeq y y |- D[..,b.1,b.2]] = - ref [g, b:block y:term , _t:aeq y y] [g, b |- M[..,b.1]] +The recursive function ref encodes the proof reflexivity for terms. The type signature reads: for all contexts g that have schema aeqCtx, for all terms M, we have a proof that [ g |- aeq M M].}}% +rec ref : {gamma:aeqCtx} {M:[gamma |- term]} [gamma |- aeq M M] = +mlam gamma => mlam M => case [gamma |- M] of +| [gamma |- #p.1] => [gamma |- #p.2] + +| [gamma |- lam \x. M] => + let [gamma,b:block y:term , _t:aeq y y |- D[..,b.1,b.2]] = + ref [gamma, b:block y:term , _t:aeq y y] [gamma, b |- M[..,b.1]] in - [g |- ae_l \x. \w. D] + [gamma |- ae_l \x. \w. D] -| [g |- app (M1[..]) (M2[..])] => - let [g |- D1[..]] = ref [g] [g |- M1[..] ] in - let [g |- D2[..]] = ref [g] [g |- M2[..] ] in - [g |- ae_a (D1[..]) (D2[..])] +| [gamma |- app M1 M2] => + let [gamma |- D1] = ref [gamma] [gamma |- M1 ] in + let [gamma |- D2] = ref [gamma] [gamma |- M2 ] in + [gamma |- ae_a D1 D2] -| [g |- tlam \a. M] => - let [g,b:block a:tp , _t:atp a a |- D[..,b.1,b.2]] = - ref [g, b:block a:tp , _t:atp a a] [g, b |- M[..,b.1]] +| [gamma |- tlam \a. M] => + let [gamma,b:block a:tp , _t:atp a a |- D[..,b.1,b.2]] = + ref [gamma, b:block a:tp , _t:atp a a] [gamma, b |- M[..,b.1]] in - [g |- ae_tl \x. \w. D] + [gamma |- ae_tl \x. \w. D] -| [g |- tapp (M[..]) (T[..])] => - let [g |- D1[..]] = ref [g] [g |- M[..] ] in - let [g |- D2[..]] = reftp [g] [g |- T[..] ] in - [g |- ae_ta (D1[..]) (D2[..])] +| [gamma |- tapp M T] => + let [gamma |- D1] = ref [gamma] [gamma |- M ] in + let [gamma |- D2] = reftp [gamma] [gamma |- T ] in + [gamma |- ae_ta D1 D2] ; %{{This time, there are five possible cases for our meta-variable M: }}% % ----------------------------------------------------------------- % % General transitivity is admissible %{{## Proof of Transitivity for Types}}% -rec transtp: (g:atpCtx) - [g |- atp (T[..]) (R[..])] -> [g |- atp (R[..]) (S[..])] - -> [g |- atp (T[..]) (S[..])] = +rec transtp: (gamma:atpCtx) + [gamma |- atp T R] -> [gamma |- atp R S] + -> [gamma |- atp T S] = fn ae1 => fn ae2 => case ae1 of -| [g |- #p.2[..]] => ae2 +| [gamma |- #p.2] => ae2 -| [g |- at_al \a.\u. D1[..,a,u]] => - let [g |- at_al \a.\u. D2[..,a,u]] = ae2 in - let [g, b:block a:tp , _t:atp a a |- D[..,b.1,b.2]] = - transtp [g, b:block a:tp , _t:atp a a |- D1[..,b.1,b.2]] - [g, b |- D2[..,b.1,b.2]] +| [gamma |- at_al \a.\u. D1[..,a,u]] => + let [gamma |- at_al \a.\u. D2[..,a,u]] = ae2 in + let [gamma, b:block a:tp , _t:atp a a |- D[..,b.1,b.2]] = + transtp [gamma, b:block a:tp , _t:atp a a |- D1[..,b.1,b.2]] + [gamma, b |- D2[..,b.1,b.2]] in - [g |- at_al \a. \u. D[..,a,u]] + [gamma |- at_al \a. \u. D[..,a,u]] -| [g |- at_arr (D1[..]) (D2[..])] => - let [g |- at_arr (D3[..]) (D4[..])] = ae2 in - let [g |- D[..]] = transtp [g |- D1[..]] [g |- D3[..]] in - let [g |- D'[..]] = transtp [g |- D2[..]] [g |- D4[..]] in - [g |- at_arr (D[..]) (D'[..])] +| [gamma |- at_arr D1 D2] => + let [gamma |- at_arr D3 D4] = ae2 in + let [gamma |- D] = transtp [gamma |- D1] [gamma |- D3] in + let [gamma |- D'] = transtp [gamma |- D2] [gamma |- D4] in + [gamma |- at_arr D D'] ; %{{## Proof of Transitivity for Terms}}% -rec trans: (g:aeqCtx) - [g |- aeq (T[..]) (R[..])] -> [g |- aeq (R[..]) (S[..])] - -> [g |- aeq (T[..]) (S[..])] = +rec trans: (gamma:aeqCtx) + [gamma |- aeq T R] -> [gamma |- aeq R S] + -> [gamma |- aeq T S] = fn ae1 => fn ae2 => case ae1 of -| [g |- #p.2[..]] => ae2 +| [gamma |- #p.2] => ae2 -| [g |- ae_l \x.\u. D1] => - let [g |- ae_l \x.\u. D2] = ae2 in - let [g, b:block x:term , _t:aeq x x |- D[..,b.1,b.2]] = - trans [g, b:block x':term , _t:aeq x' x' |- D1[..,b.1,b.2]] - [g, b |- D2[..,b.1,b.2]] +| [gamma |- ae_l \x.\u. D1] => + let [gamma |- ae_l \x.\u. D2] = ae2 in + let [gamma, b:block x:term , _t:aeq x x |- D[..,b.1,b.2]] = + trans [gamma, b:block x':term , _t:aeq x' x' |- D1[..,b.1,b.2]] + [gamma, b |- D2[..,b.1,b.2]] in - [g |- ae_l \x. \u. D] + [gamma |- ae_l \x. \u. D] -| [g |- ae_a (D1[..]) (D2[..])] => - let [g |- ae_a (D3[..]) (D4[..])] = ae2 in - let [g |- D[..]] = trans [g |- D1[..]] [g |- D3[..]] in - let [g |- D'[..]] = trans [g |- D2[..]] [g |- D4[..]] in - [g |- ae_a (D[..]) (D'[..])] - -| [g |- ae_tl \a.\u. D1[..,a,u]] => - let [g |- ae_tl \a.\u. D2[..,a,u]] = ae2 in - let [g, b:block a:tp , _t:atp a a |- D[..,b.1,b.2]] = - trans [g, b:block a:tp , _t:atp a a |- D1[..,b.1,b.2]] - [g, b |- D2[..,b.1,b.2]] +| [gamma |- ae_a D1 D2] => + let [gamma |- ae_a D3 D4] = ae2 in + let [gamma |- D] = trans [gamma |- D1] [gamma |- D3] in + let [gamma |- D'] = trans [gamma |- D2] [gamma |- D4] in + [gamma |- ae_a D D'] + +| [gamma |- ae_tl \a.\u. D1[..,a,u]] => + let [gamma |- ae_tl \a.\u. D2[..,a,u]] = ae2 in + let [gamma, b:block a:tp , _t:atp a a |- D[..,b.1,b.2]] = + trans [gamma, b:block a:tp , _t:atp a a |- D1[..,b.1,b.2]] + [gamma, b |- D2[..,b.1,b.2]] in - [g |- ae_tl \x. \u. D] + [gamma |- ae_tl \x. \u. D] -| [g |- ae_ta (D1[..]) (Q1[..])] => - let [g |- ae_ta (D2[..]) (Q2[..])] = ae2 in - let [g |- D[..]] = trans [g |- D1[..]] [g |- D2[..]] in - let [g |- Q[..]] = transtp [g |- Q1[..]] [g |- Q2[..]] in - [g |- ae_ta (D[..]) (Q[..])] +| [gamma |- ae_ta D1 Q1] => + let [gamma |- ae_ta D2 Q2] = ae2 in + let [gamma |- D] = trans [gamma |- D1] [gamma |- D2] in + let [gamma |- Q] = transtp [gamma |- Q1] [gamma |- Q2] in + [gamma |- ae_ta D Q] ; % ----------------------------------------------------------------- % % General symmetry is admissible %{{## Proof of Symmetry for Types}}% -rec symtp: (g:atpCtx) - [g |- atp (T[..]) (R[..])] -> [g |- atp (R[..]) (T[..])] = +rec symtp: (gamma:atpCtx) + [gamma |- atp T R] -> [gamma |- atp R T] = fn ae => case ae of -| [g |- #p.2[..]] => ae -| [g |- at_al \x.\u. D] => - let [g, b:block a:tp , _t:atp a a |- D'[..,b.1,b.2]] = - symtp [g, b:block a:tp, _t:atp a a |- D[..,b.1,b.2]] in - [g |- at_al \x.\u. D'] -| [g |- at_arr (D1[..]) (D2[..])] => - let [g |- D1'[..]] = symtp [g |- D1[..]] in - let [g |- D2'[..]] = symtp [g |- D2[..]] in - [g |- at_arr (D1'[..]) (D2'[..])] +| [gamma |- #p.2] => ae +| [gamma |- at_al \x.\u. D] => + let [gamma, b:block a:tp , _t:atp a a |- D'[..,b.1,b.2]] = + symtp [gamma, b:block a:tp, _t:atp a a |- D[..,b.1,b.2]] in + [gamma |- at_al \x.\u. D'] +| [gamma |- at_arr D1 D2] => + let [gamma |- D1'] = symtp [gamma |- D1] in + let [gamma |- D2'] = symtp [gamma |- D2] in + [gamma |- at_arr D1' D2'] ; %{{## Proof of Symmetry for Terms}}% -rec sym: (g:aeqCtx) - [g |- aeq (T[..]) (R[..])] -> [g |- aeq (R[..]) (T[..])] = +rec sym: (gamma:aeqCtx) + [gamma |- aeq T R] -> [gamma |- aeq R T] = fn ae => case ae of -| [g |- #p.2[..]] => ae -| [g |- ae_l \x.\u. D] => - let [g, b:block x:term , _t:aeq x x |- D'[..,b.1,b.2]] = - sym [g, b:block x:term, _t:aeq x x |- D[..,b.1,b.2]] in - [g |- ae_l \x.\u. D'] -| [g |- ae_a (D1[..]) (D2[..])] => - let [g |- D1'[..]] = sym [g |- D1[..]] in - let [g |- D2'[..]] = sym [g |- D2[..]] in - [g |- ae_a (D1'[..]) (D2'[..])] -| [g |- ae_tl \x.\u. D] => - let [g, b:block a:tp , _t:atp a a |- D'[..,b.1,b.2]] = - sym [g, b:block a:tp, _t:atp a a |- D[..,b.1,b.2]] in - [g |- ae_tl \x.\u. D'] -| [g |- ae_ta (D[..]) (Q[..])] => - let [g |- D'[..]] = sym [g |- D[..]] in - let [g |- Q'[..]] = symtp [g |- Q[..]] in - [g |- ae_ta (D'[..]) (Q'[..])] +| [gamma |- #p.2] => ae +| [gamma |- ae_l \x.\u. D] => + let [gamma, b:block x:term , _t:aeq x x |- D'[..,b.1,b.2]] = + sym [gamma, b:block x:term, _t:aeq x x |- D[..,b.1,b.2]] in + [gamma |- ae_l \x.\u. D'] +| [gamma |- ae_a D1 D2] => + let [gamma |- D1'] = sym [gamma |- D1] in + let [gamma |- D2'] = sym [gamma |- D2] in + [gamma |- ae_a D1' D2'] +| [gamma |- ae_tl \x.\u. D] => + let [gamma, b:block a:tp , _t:atp a a |- D'[..,b.1,b.2]] = + sym [gamma, b:block a:tp, _t:atp a a |- D[..,b.1,b.2]] in + [gamma |- ae_tl \x.\u. D'] +| [gamma |- ae_ta D Q] => + let [gamma |- D'] = sym [gamma |- D] in + let [gamma |- Q'] = symtp [gamma |- Q] in + [gamma |- ae_ta D' Q'] ; % ----------------------------------------------------------------- % % Completeness %{{## Proof of Completeness for Types}}% -rec ctp: (g:dtpCtx) - [g |- dtp (T[..]) (S[..])] -> [g |- atp (T[..]) (S[..])] = +rec ctp: (gamma:dtpCtx) + [gamma |- dtp T S] -> [gamma |- atp T S] = fn e => case e of -| [g |- #p.3[..]] => [g |- #p.2[..]] -| [g |- dt_r] => reftp [g] [g |- _ ] -| [g |- dt_arr (F1[..]) (F2[..])] => - let [g |- D1[..]] = ctp [g |- F1[..]] in - let [g |- D2[..]] = ctp [g |- F2[..]] in - [g |- at_arr (D1[..]) (D2[..])] - -| [g |- dt_al (\x.\u. F)] => - let [g,b:block a:tp,u:atp a a , _t:dtp a a |- D[..,b.1,b.2]] = - ctp [g, b:block a:tp, u:atp a a , _t:dtp a a |- F[..,b.1,b.3]] +| [gamma |- #p.3] => [gamma |- #p.2] +| [gamma |- dt_r] => reftp [gamma] [gamma |- _ ] +| [gamma |- dt_arr F1 F2] => + let [gamma |- D1] = ctp [gamma |- F1] in + let [gamma |- D2] = ctp [gamma |- F2] in + [gamma |- at_arr D1 D2] + +| [gamma |- dt_al (\x.\u. F)] => + let [gamma,b:block a:tp,u:atp a a , _t:dtp a a |- D[..,b.1,b.2]] = + ctp [gamma, b:block a:tp, u:atp a a , _t:dtp a a |- F[..,b.1,b.3]] in - [g |- at_al (\x.\v. D)] - - | [g |- dt_t (F1[..]) (F2[..])] => - let [g |- D2[..]] = ctp [g |- F2[..]] in - let [g |- D1[..]] = ctp [g |- F1[..]] in - transtp [g |- D1[..]] [g |- D2[..]] -| [g |- dt_s (F[..])] => - let [g |- D[..]] = ctp [g |- F[..]] in - symtp [g |- D[..]] + [gamma |- at_al (\x.\v. D)] + + | [gamma |- dt_t F1 F2] => + let [gamma |- D2] = ctp [gamma |- F2] in + let [gamma |- D1] = ctp [gamma |- F1] in + transtp [gamma |- D1] [gamma |- D2] +| [gamma |- dt_s F] => + let [gamma |- D] = ctp [gamma |- F] in + symtp [gamma |- D] ; %{{## Proof of Completeness for Terms}}% -rec ceq: (g:deqCtx) - [g |- deq (T[..]) (S[..])] -> [g |- aeq (T[..]) (S[..])] = +rec ceq: (gamma:deqCtx) + [gamma |- deq T S] -> [gamma |- aeq T S] = fn e => case e of -| [g |- #p.3[..]] => [g |- #p.2[..]] -| [g |- de_r] => ref [g] [g |- _ ] -| [g |- de_a (F1[..]) (F2[..])] => - let [g |- D1[..]] = ceq [g |- F1[..]] in - let [g |- D2[..]] = ceq [g |- F2[..]] in - [g |- ae_a (D1[..]) (D2[..])] - -| [g |- de_l (\x.\u. F)] => - let [g,b:block x:term,u:aeq x x , _t:deq x x |- D[..,b.1,b.2]] = - ceq [g, b:block x:term, u:aeq x x , _t:deq x x |- F[..,b.1,b.3]] +| [gamma |- #p.3] => [gamma |- #p.2] +| [gamma |- de_r] => ref [gamma] [gamma |- _ ] +| [gamma |- de_a F1 F2] => + let [gamma |- D1] = ceq [gamma |- F1] in + let [gamma |- D2] = ceq [gamma |- F2] in + [gamma |- ae_a D1 D2] + +| [gamma |- de_l (\x.\u. F)] => + let [gamma,b:block x:term,u:aeq x x , _t:deq x x |- D[..,b.1,b.2]] = + ceq [gamma, b:block x:term, u:aeq x x , _t:deq x x |- F[..,b.1,b.3]] in - [g |- ae_l (\x.\v. D)] + [gamma |- ae_l (\x.\v. D)] - | [g |- de_t (F1[..]) (F2[..])] => - let [g |- D2[..]] = ceq [g |- F2[..]] in - let [g |- D1[..]] = ceq [g |- F1[..]] in - trans [g |- D1[..]] [g |- D2[..]] + | [gamma |- de_t F1 F2] => + let [gamma |- D2] = ceq [gamma |- F2] in + let [gamma |- D1] = ceq [gamma |- F1] in + trans [gamma |- D1] [gamma |- D2] -| [g |- de_s (F[..])] => - let [g |- D[..]] = ceq [g |- F] in - sym [g |- D[..]] +| [gamma |- de_s F] => + let [gamma |- D] = ceq [gamma |- F] in + sym [gamma |- D] -| [g |- de_tl (\a.\u. F[..,a,u])] => - let [g,b:block a:tp,u:atp a a , _t:dtp a a |- D[..,b.1,b.2]] = - ceq [g, b:block a:tp, u: atp a a , _t:dtp a a |- F[..,b.1,b.3]] +| [gamma |- de_tl (\a.\u. F[..,a,u])] => + let [gamma,b:block a:tp,u:atp a a , _t:dtp a a |- D[..,b.1,b.2]] = + ceq [gamma, b:block a:tp, u: atp a a , _t:dtp a a |- F[..,b.1,b.3]] in - [g |- ae_tl (\x.\v. D)] - - | [g |- de_ta (F1[..]) (P2[..])] => - let [g |- Q2[..]] = ctp [g |- P2[..]] in - let [g |- D1[..]] = ceq [g |- F1[..]] in - [g |- ae_ta (D1[..]) (Q2[..])] - + [gamma |- ae_tl (\x.\v. D)] + | [gamma |- de_ta F1 P2] => + let [gamma |- Q2] = ctp [gamma |- P2] in + let [gamma |- D1] = ceq [gamma |- F1] in + [gamma |- ae_ta D1 Q2] ; diff --git a/examples/literate_beluga/0Beginner/Type_Uniqueness.bel b/examples/literate_beluga/0Beginner/Type_Uniqueness.bel index 4b9665ad2..29b8699bb 100644 --- a/examples/literate_beluga/0Beginner/Type_Uniqueness.bel +++ b/examples/literate_beluga/0Beginner/Type_Uniqueness.bel @@ -71,10 +71,10 @@ fn d => fn f => case d of Consider each case individually. }}% diff --git a/examples/literate_beluga/0Beginner/Untyped_Algorithmic_Equality_-_Context_Relation.bel b/examples/literate_beluga/0Beginner/Untyped_Algorithmic_Equality_-_Context_Relation.bel index 1e63be5dc..4c44e82ec 100755 --- a/examples/literate_beluga/0Beginner/Untyped_Algorithmic_Equality_-_Context_Relation.bel +++ b/examples/literate_beluga/0Beginner/Untyped_Algorithmic_Equality_-_Context_Relation.bel @@ -14,14 +14,15 @@ The mechanization highlights several aspects: %{{

Syntax

Untyped lambda-terms are introduced with LF-level declarations. The context schemas translate directly from the ORBI file. }}% -tm: type. -app: tm -> tm -> tm. -lam: (tm -> tm) -> tm. - -aeq: tm -> tm -> type. -ae_l: ({x:tm} aeq x x -> aeq (M x) (N x)) - -> aeq (lam (\x. M x)) (lam (\x. N x)). -ae_a: aeq M1 N1 -> aeq M2 N2 -> aeq (app M1 M2) (app N1 N2). +LF tm: type = +| app: tm -> tm -> tm +| lam: (tm -> tm) -> tm; + +LF aeq: tm -> tm -> type = +| ae_l: ({x:tm} aeq x x -> aeq (M x) (N x)) + -> aeq (lam \x. M x) (lam \x. N x) +| ae_a: aeq M1 N1 -> aeq M2 N2 -> aeq (app M1 M2) (app N1 N2) +; @@ -32,71 +33,72 @@ schema xaG = block x:tm, u:aeq x x; ## Context Relationships via Inductive Datatypes The key to express context weakening and strengthening is the ability to relate two contexts via a substitution. In Beluga, we can describe context relations using inductive inductives as a relation between context phi, context psi, and a substitution #S that maps variables from phi to the context psi, formally #S:[psi |- phi] as follows:}}% + inductive Ctx_xaR : {phi:xG} {psi: xaG} {#S:[psi |- phi]} ctype = | Nil_xa : Ctx_xaR [] [] [ |- ^ ] -| Cons_xa : Ctx_xaR [phi] [psi] [psi |- #S[..] ] - -> Ctx_xaR [phi, x:tm] [psi, b: block (x:tm,u:aeq x x)] [ psi, b |- #S[..],b.1 ] +| Cons_xa : Ctx_xaR [phi] [psi] [psi |- #S ] + -> Ctx_xaR [phi, x:tm] [psi, b: block (x:tm,u:aeq x x)] [ psi, b |- #S[..] ,b.1 ] ; -%{{The first-class substitution variable #S has domain phi and range psi. If #S relates contexts phi and psi, then the substitution #S b.1 relates phi, x:tm to psi, b:block (x:tm,u:aeq x x) via constructor Cons_xaR.}}% +%{{The first-class substitution variable #S has domain phi and range psi. If #S relates contexts phi and psi, then the substitution #S, b.1 relates phi, x:tm to psi, b:block (x:tm,u:aeq x x) via constructor Cons_xaR.}}% inductive EqV : {phi:xG}{psi:xaG}{#S:[psi |- phi]} [phi |- tm] -> [psi |- tm] -> ctype = | EqV_v: EqV [phi, x:tm] [psi, b: block (x:tm,u:aeq x x)] [ psi, b:block (x:tm, u:aeq x x) |- #S[..],b.1 ] [phi, x:tm |- x] [psi, b:block (x:tm, u:aeq x x) |- b.1 ] -| EqV_p : EqV [phi] [psi] [psi |- #S[..] ] [phi |- #p[..]][psi |- #q.1[..]] +| EqV_p : EqV [phi] [psi] [psi |- #S ] [phi |- #p][psi |- #q.1] -> EqV [phi, x:tm] [psi, b: block (x:tm,u:aeq x x)] [ psi, b |- #S[..],b.1 ] [phi, x:tm |- #p[..]] [psi, b:block (x:tm, u:aeq x x) |- #q.1[..] ] ; inductive Eq : {phi:xG}{psi:xaG}{#S:[psi |- phi]} [phi |- tm] -> [psi |- tm] -> ctype = -| Eq_v: EqV [phi] [psi] [psi |- #S[..]] [phi |- #p[..] ] [psi |- #q.1[..]] - -> Eq [phi] [psi] [psi |- #S[..]] [phi |- #p[..] ] [psi |- #q.1[..]] +| Eq_v: EqV [phi] [psi] [psi |- #S] [phi |- #p ] [psi |- #q.1] + -> Eq [phi] [psi] [psi |- #S] [phi |- #p ] [psi |- #q.1] | Eq_a: - Eq [phi] [psi] [psi |- #S[..] ] [phi |- M[..]] [psi |- M'[..]] -> - Eq [phi] [psi] [psi |- #S[..] ] [phi |- N[..]] [psi |- N'[..]] -> - Eq [phi] [psi] [psi |- #S[..] ] [phi |- app (M[..]) (N[..])] [psi |- app (M'[..]) (N'[..])] + Eq [phi] [psi] [psi |- #S ] [phi |- M] [psi |- M'] -> + Eq [phi] [psi] [psi |- #S ] [phi |- N] [psi |- N'] -> + Eq [phi] [psi] [psi |- #S ] [phi |- app M N] [psi |- app M' N'] | Eq_l : Eq [phi,x:tm] [psi,b:block (x:tm, u:aeq x x)] [psi, b:block (x:tm, u:aeq x x) |- #S[..],b.1] [phi,x:tm |- M] [psi, b:block (x:tm, u:aeq x x) |- M'[..,b.1]] - -> Eq [phi] [psi] [psi |- #S[..] ] + -> Eq [phi] [psi] [psi |- #S ] [phi |- lam \x. M] [psi |- lam \x. M'] ; %{{

Proof of Reflexivity, Compact version

-The recursive function refl of type {phi:xG}{M: [phi |- tm]} Ctx_xaR [phi] [psi] [ psi |- #S[..] ] -> [psi |- aeq (M #S[..]) (M #S[..])]: for all contexts phi and psi that have schema xG and xaG, respectively, if we have a substitution #S s.t. #S:[psi |- phi] then for all terms M depending on phi, we have a proof that [ psi |- aeq (#p #S[..]) (#p #S[..])]." Since the term M depends only on the context phi, it is explicitly weakened through applying #S to move it to the context psi.}}% +The recursive function refl of type {phi:xG}{M: [phi |- tm]} Ctx_xaR [phi] [psi] [ psi |- #S ] -> [psi |- aeq (M #S) (M #S)]: for all contexts phi and psi that have schema xG and xaG, respectively, if we have a substitution #S s.t. #S:[psi |- phi] then for all terms M depending on phi, we have a proof that [ psi |- aeq (#p #S) (#p #S)]." Since the term M depends only on the context phi, it is explicitly weakened through applying #S to move it to the context psi.}}% rec ctx_membership : {#p: [phi |- tm] } - Ctx_xaR [phi] [psi] [ psi |- #S[..] ] -> + Ctx_xaR [phi] [psi] [ psi |- #S ] -> [psi |- aeq #p[#S] #p[#S]] = -mlam #p => fn cr => let (cr : Ctx_xaR [phi] [psi] [ psi |- #S[..] ]) = cr in -case [phi |- #p[..]] of +mlam #p => fn cr => let (cr : Ctx_xaR [phi] [psi] [ psi |- #S ]) = cr in +case [phi |- #p] of | [phi, x:tm |- x] => let Cons_xa cr' = cr in - let (cr' : Ctx_xaR [phi] [psi] [ psi |- #S[..] ]) = cr' in + let (cr' : Ctx_xaR [phi] [psi] [ psi |- #S ]) = cr' in [psi, b: block (x:tm, u:aeq x x) |- b.2] | [phi, x:tm |- #p[..]] => let Cons_xa cr' = cr in - let [psi |- E[..]] = ctx_membership [phi |- #p] cr' in + let [psi |- E] = ctx_membership [phi |- #p] cr' in [psi, b: block (x:tm,u:aeq x x) |- E[..] ] ; % Compact version rec refl : {phi:xG}{M: [phi |- tm]} - Ctx_xaR [phi] [psi] [ psi |- #S[..] ] -> + Ctx_xaR [phi] [psi] [ psi |- #S ] -> [psi |- aeq M[#S] M[#S]] = -mlam phi => mlam M => fn cr => case [phi |- M[..]] of -| [phi |- #p[..]] => ctx_membership [phi |- #p] cr +mlam phi => mlam M => fn cr => case [phi |- M] of +| [phi |- #p] => ctx_membership [phi |- #p] cr -| [phi |- app (M[..] ) (N[..])] => - let [psi |- D1[..] ] = refl [phi] [phi |- M[..]] cr in - let [psi |- D2[..] ] = refl [phi] [phi |- N[..]] cr in - [psi |- ae_a (D1[..]) (D2[..]) ] +| [phi |- app (M ) N] => + let [psi |- D1 ] = refl [phi] [phi |- M] cr in + let [psi |- D2 ] = refl [phi] [phi |- N] cr in + [psi |- ae_a D1 D2 ] | [phi |- lam \x.M] => @@ -105,51 +107,51 @@ mlam phi => mlam M => fn cr => case [phi |- M[..]] of [psi |- ae_l \x.\u. D] ; -%{{In the application case, we appeal to the induction hypothesis on [phi |- M1[..]] and [ |- M2 ::] through a recursive call. Since the context phi and the context psi do not change, we can simply make the recursive all on [phi |- M1 ::] and [phi |- M2 ::] respectively using the relation cr. +%{{In the application case, we appeal to the induction hypothesis on [phi |- M] and [ |- N] through a recursive call. Since the context phi and the context psi do not change, we can simply make the recursive all on [phi |- M] and [phi |- M] respectively using the relation cr.

-When we have [phi |- lam \x.M :: x], we want to appeal to the induction hypothesis on [phi |- x:tm. M ::x]. In this instance, we also need a witness relating the context [phi |- x:tm. M ::x] to the context [psi, b:block (x:tm,u:aeq x x)]. Recall that cr stands for Ctx_xaR [phi] [psi] [psi |- #S]. Therefore, by Cons_xa, we know there exists Ctx_xaR [phi ,x:tm] [psi ,b:block (x:tm,u:aeq x x)] [psi, b |- #S b.1] and we appeal to the induction hypothesis by reflR [phi,x:tm] [phi,x:tm.M ::x] (Cons_xa cr). +When we have [phi |- lam \x.M ], we want to appeal to the induction hypothesis on [phi, x:tm |- M]. In this instance, we also need a witness relating the context [phi, x:tm |- M] to the context [psi, b:block (x:tm,u:aeq x x)]. Recall that cr stands for Ctx_xaR [phi] [psi] [psi |- #S]. Therefore, by Cons_xa, we know there exists Ctx_xaR [phi ,x:tm] [psi ,b:block (x:tm,u:aeq x x)] [psi, b |- #S, b.1] and we appeal to the induction hypothesis by reflR [phi,x:tm] [phi,x:tm.M] (Cons_xa cr).

-Finally, we take a close look at the variable case. We distinguish two different cases depending on the position of the variable in the context by pattern matching on the shape of phi. If [phi,x:tm |- x], then we inspect the context relation cr. Pattern matching forces the original context phi to be phi,x:tm. By pattern matching on cr', we observe that there exists a relation cr', s.t. Ctx_xaR [phi] [psi] [psi |- #S]. Moreover, psi = psi,b:block (x:tm,u:aeq x x) and #S = #S b.1 where the left hand side denotes the original context and substitution, while the right hand side shows the context and substitution refinement after pattern matching. We must show that there exists a proof for aeq x x in the context psi, b:block (x:tm,u:aeq x x). This is simply b.2.}}% +Finally, we take a close look at the variable case. We distinguish two different cases depending on the position of the variable in the context by pattern matching on the shape of phi. If [phi,x:tm |- x], then we inspect the context relation cr. Pattern matching forces the original context phi to be phi,x:tm. By pattern matching on cr', we observe that there exists a relation cr', s.t. Ctx_xaR [phi] [psi] [psi |- #S]. Moreover, psi = psi,b:block (x:tm,u:aeq x x) and #S = #S, b.1 where the left hand side denotes the original context and substitution, while the right hand side shows the context and substitution refinement after pattern matching. We must show that there exists a proof for aeq x x in the context psi, b:block (x:tm,u:aeq x x). This is simply b.2.}}% %{{

-Following we generalize reasoning about terms which contain substitution variables, reasoning explicitly about equality between terms M and M #S[..]. Since we cannot pattern match directly on M #S[..] (because #S is a general substitution and we do not enforce on the type-level that it is a variable-variable substitution) we cannot use unification to solve equations; If #S would be known to be a pattern substitution, then we could solve equations such as M #S[..] = app (M1[..]) (M2[..]); we hence encode such equalities explicitly. +Following we generalize reasoning about terms which contain substitution variables, reasoning explicitly about equality between terms M and M[#S]. Since we cannot pattern match directly on M[#S] (because #S is a general substitution and we do not enforce on the type-level that it is a variable-variable substitution) we cannot use unification to solve equations; If #S would be known to be a pattern substitution, then we could solve equations such as M[#S] = app M1 M2; we hence encode such equalities explicitly.

Proof of Reflexivity, Expanded

}}% rec ctx_member : {#p: [phi |- tm] } - Ctx_xaR [phi] [psi] [ psi |- #S[..] ] -> - EqV [phi] [psi] [ psi |- #S[..] ] [phi |- #p[..]] [psi |- M[..]] -> - [psi |- aeq (M[..]) (M[..])] = + Ctx_xaR [phi] [psi] [ psi |- #S ] -> + EqV [phi] [psi] [ psi |- #S ] [phi |- #p] [psi |- M] -> + [psi |- aeq M M] = -mlam #p => fn cr => fn m => let (cr : Ctx_xaR [phi] [psi] [ psi |- #S[..] ]) = cr in -case [phi |- #p[..]] of +mlam #p => fn cr => fn m => let (cr : Ctx_xaR [phi] [psi] [ psi |- #S ]) = cr in +case [phi |- #p] of | [phi, x:tm |- x] => let Cons_xa cr' = cr in let EqV_v = m in - let (cr' : Ctx_xaR [phi] [psi] [ psi |- #S[..] ]) = cr' in + let (cr' : Ctx_xaR [phi] [psi] [ psi |- #S ]) = cr' in [psi, b: block (x:tm, u:aeq x x) |- b.2] | [phi, x:tm |- #p[..]] => let Cons_xa cr' = cr in let EqV_p m' = m in - let [psi |- E[..]] = ctx_member [phi |- #p] cr' m' in - [psi, b: block (x:tm,u:aeq x x) |- E[..] ] + let [psi |- E] = ctx_member [phi |- #p] cr' m' in + [psi, b: block (x:tm,u:aeq x x) |- E[..]] ; rec reflR : {phi:xG}{M: [phi |- tm]} - Ctx_xaR [phi] [psi] [ psi |- #S[..] ] -> -Eq [phi] [psi] [ psi |- #S[..] ] [phi |- M[..]] [psi |- M'[..]] -> - [psi |- aeq (M'[..]) (M'[..])] = - mlam phi => mlam M => fn cr => fn m => case [phi |- M[..]] of -| [phi |- #p[..] ] => + Ctx_xaR [phi] [psi] [ psi |- #S ] -> +Eq [phi] [psi] [ psi |- #S ] [phi |- M] [psi |- M'] -> + [psi |- aeq (M') (M')] = + mlam phi => mlam M => fn cr => fn m => case [phi |- M] of +| [phi |- #p ] => let Eq_v m' = m in - ctx_member [phi |- #p[..]] cr m' -| [phi |- app (M[..] ) (N[..])] => + ctx_member [phi |- #p] cr m' +| [phi |- app (M ) N] => let Eq_a m1 m2 = m in - let [psi |- D1[..] ] = reflR [phi] [phi |- M[..]] cr m1 in - let [psi |- D2[..] ] = reflR [phi] [phi |- N[..]] cr m2 in - [psi |- ae_a (D1[..]) (D2[..]) ] + let [psi |- D1 ] = reflR [phi] [phi |- M] cr m1 in + let [psi |- D2 ] = reflR [phi] [phi |- N] cr m2 in + [psi |- ae_a D1 D2 ] | [phi |- lam \x.M] => let Eq_l m' = m in @@ -158,52 +160,52 @@ Eq [phi] [psi] [ psi |- #S[..] ] [phi |- M[..]] [psi |- M'[..]] -> [psi |- ae_l \x.\u. D] ; -rec transV : Ctx_xaR [phi] [psi] [ psi |- #S[..] ] -> -EqV [phi] [psi] [ psi |- #S[..] ] [phi |- M[..]] [psi |- #p.1[..]] -> -EqV [phi] [psi] [ psi |- #S[..] ] [phi |- N[..]] [psi |- #p.1[..]] -> -EqV [phi] [psi] [ psi |- #S[..] ] [phi |- L[..]] [psi |- #p.1[..]] -> - [psi |- aeq (#p.1[..]) (#p.1[..])] = +rec transV : Ctx_xaR [phi] [psi] [ psi |- #S ] -> +EqV [phi] [psi] [ psi |- #S ] [phi |- M] [psi |- #p.1] -> +EqV [phi] [psi] [ psi |- #S ] [phi |- N] [psi |- #p.1] -> +EqV [phi] [psi] [ psi |- #S ] [phi |- L] [psi |- #p.1] -> + [psi |- aeq (#p.1) (#p.1)] = fn cr => fn m => fn n => fn l => case m of | EqV_v => let EqV_v = n in let EqV_v = l in let (Cons_xa cr') = cr in - let (cr' : Ctx_xaR [phi] [psi] [psi |- #S[..] ]) = cr' in + let (cr' : Ctx_xaR [phi] [psi] [psi |- #S ]) = cr' in [psi, b:block (x:tm, u:aeq x x) |- b.2] | EqV_p m' => let EqV_p n' = n in let EqV_p l' = l in let (Cons_xa cr') = cr in - let [psi |- E[..] ] = transV cr' m' n' l' in + let [psi |- E ] = transV cr' m' n' l' in [psi, b:block (x:tm, u:aeq x x) |- E[..]] ; rec transR: -Ctx_xaR [phi] [psi] [ psi |- #S[..] ] -> -Eq [phi] [psi] [ psi |- #S[..] ] [phi |- M[..]] [psi |- M'[..]] -> -Eq [phi] [psi] [ psi |- #S[..] ] [phi |- N[..]] [psi |- N'[..]] -> -Eq [phi] [psi] [ psi |- #S[..] ] [phi |- L[..]] [psi |- L'[..]] -> -[psi |- aeq (M'[..]) (N'[..])] -> [psi |- aeq (N'[..]) (L'[..])] --> [psi |- aeq (M'[..]) (L'[..])] = +Ctx_xaR [phi] [psi] [ psi |- #S ] -> +Eq [phi] [psi] [ psi |- #S ] [phi |- M] [psi |- M'] -> +Eq [phi] [psi] [ psi |- #S ] [phi |- N] [psi |- N'] -> +Eq [phi] [psi] [ psi |- #S ] [phi |- L] [psi |- L'] -> +[psi |- aeq (M') (N')] -> [psi |- aeq (N') (L')] +-> [psi |- aeq (M') (L')] = fn cr => fn m => fn n => fn l => fn d1 => fn d2 => case d1 of -| [psi |- #p.2[..]] => - let [psi |- #q.2[..] ] = d2 in +| [psi |- #p.2] => + let [psi |- #q.2 ] = d2 in let Eq_v m' = m in let (m' : EqV [phi] [psi, b : block (x:tm, u:aeq x x)] [psi, b:block (x:tm, u:aeq x x) |- #S[..]] - [phi |- #r[..]] [psi, b: block (x:tm, u:aeq x x) |- #q.1[..]] ) = m' in + [phi |- #r] [psi, b: block (x:tm, u:aeq x x) |- #q.1[..]] ) = m' in ctx_member [phi |- #r] cr m' -| [psi |- ae_a (D1[..]) (D2[..])] => - let [psi |- ae_a (F1[..]) (F2[..])] = d2 in +| [psi |- ae_a D1 D2] => + let [psi |- ae_a (F1) (F2)] = d2 in let Eq_a m1 m2 = m in let Eq_a n1 n2 = n in let Eq_a l1 l2 = l in - let [psi |- E1[..]] = transR cr m1 n1 l1 - [psi |- D1[..]] [psi |- F1[..]] in - let [psi |- E2[..]] = transR cr m2 n2 l2 - [psi |- D2[..]] [psi |- F2[..]] in + let [psi |- E1] = transR cr m1 n1 l1 + [psi |- D1] [psi |- F1] in + let [psi |- E2] = transR cr m2 n2 l2 + [psi |- D2] [psi |- F2] in - [psi |- ae_a (E1[..]) (E2[..])] + [psi |- ae_a E1 E2] | [psi |- ae_l \x.\u. D1] => let [psi |- ae_l \x.\u. D2] = d2 in @@ -237,7 +239,7 @@ schema daG = block x: tm, ae_v:aeq x x, de_v:deq x x ; % --------------------------------------------------------------------------- inductive Ctx_xdR : {phi:xG} {psi: xdG} {#S:[psi |- phi]} ctype = | Nil_xd : Ctx_xdR [] [] [ |- ^ ] -| Cons_xd : Ctx_xdR [phi] [psi] [psi |- #S[..] ] +| Cons_xd : Ctx_xdR [phi] [psi] [psi |- #S ] -> Ctx_xdR [phi, x:tm] [psi, b: block (x:tm,u:deq x x)] [ psi, b |- #S[..],b.1 ] ; @@ -255,68 +257,68 @@ inductive EqV' : {phi:xG}{psi:xdG}{#S:[psi |- phi]} [phi |- tm] -> [psi |- tm] - [phi, x:tm |- x] [psi, b:block (x:tm, u:deq x x) |- b.1 ] -| EqV'_p : EqV' [phi] [psi] [psi |- #S[..] ] [phi |- #p[..]][psi |- #q.1[..]] +| EqV'_p : EqV' [phi] [psi] [psi |- #S ] [phi |- #p][psi |- #q.1] -> EqV' [phi, x:tm] [psi, b: block (x:tm,u:deq x x)] [ psi, b |- #S[..],b.1 ] [phi, x:tm |- #p[..]] [psi, b:block (x:tm, u:deq x x) |- #q.1[..] ] ; inductive Eq' : {phi:xG}{psi:xdG}{#S:[psi |- phi]} [phi |- tm] -> [psi |- tm] -> ctype = -| Eq'_v : EqV' [phi] [psi] [psi |- #S[..] ] [phi |- #p[..]][psi |- #q.1[..]] - -> Eq' [phi] [psi] [psi |- #S[..] ] [phi |- #p[..]][psi |- #q.1[..]] +| Eq'_v : EqV' [phi] [psi] [psi |- #S ] [phi |- #p][psi |- #q.1] + -> Eq' [phi] [psi] [psi |- #S ] [phi |- #p][psi |- #q.1] | Eq'_a: - Eq' [phi] [psi] [psi |- #S[..] ] [phi |- M[..]] [psi |- M'[..]] -> - Eq' [phi] [psi] [psi |- #S[..] ] [phi |- N[..]] [psi |- N'[..]] -> - Eq' [phi] [psi] [psi |- #S[..] ] [phi |- app (M[..]) (N[..])] [psi |- app (M'[..]) N'] + Eq' [phi] [psi] [psi |- #S ] [phi |- M] [psi |- M'] -> + Eq' [phi] [psi] [psi |- #S ] [phi |- N] [psi |- N'] -> + Eq' [phi] [psi] [psi |- #S ] [phi |- app M N] [psi |- app (M') N'] | Eq'_l : Eq' [phi,x:tm] [psi,b:block (x:tm, u:deq x x)] [psi, b:block (x:tm, u:deq x x) |- #S[..],b.1] [phi,x:tm |- M] [psi, b:block (x:tm, u:deq x x) |- M'[..,b.1]] - -> Eq' [phi] [psi] [psi |- #S[..] ] + -> Eq' [phi] [psi] [psi |- #S ] [phi |- lam \x. M] [psi |- lam \x. M'] ; inductive Equal_xaG : (psi:xaG) [psi |- tm] -> [psi |- tm] -> ctype = -| Refl_xaG : Equal_xaG [psi |- M[..]] [psi |- M[..]] ; +| Refl_xaG : Equal_xaG [psi |- M] [psi |- M] ; inductive Equal_xG : (psi:xG) [psi |- tm] -> [psi |- tm] -> ctype = -| Refl_xG : Equal_xG [psi |- M[..]] [psi |- M[..]] ; +| Refl_xG : Equal_xG [psi |- M] [psi |- M] ; % for all Ld given Ctx_xdR [gamma] [phi] [phi |- #T..[]], -% there exists an L s.t. Eq' [gamma] [phi] [phi |- #T[..] [gamma |- L] [phi |- Ld[..]] +% there exists an L s.t. Eq' [gamma] [phi] [phi |- #T [gamma |- L] [phi |- Ld] inductive ExistsEq' : {gamma:xG}{phi: xdG}{#S : [phi |- gamma]} {L: [phi |- tm]} ctype = | ExistsEq' : - {L:[gamma |- tm]} Eq' [gamma] [phi] [phi |- #T[..]] [gamma |- L[..]] [phi |- Ld[..]] --> ExistsEq' [gamma] [phi] [phi |- #T[..] ] [phi |- Ld[..]] + {L:[gamma |- tm]} Eq' [gamma] [phi] [phi |- #T] [gamma |- L] [phi |- Ld] +-> ExistsEq' [gamma] [phi] [phi |- #T ] [phi |- Ld] | ExistsEqV' : - {#p:[gamma |- tm]} EqV' [gamma] [phi] [phi |- #T[..]] [gamma |- #p[..]] [phi |- #q.1[..]] --> ExistsEq' [gamma] [phi] [phi |- #T[..] ] [phi |- #q.1[..]] + {#p:[gamma |- tm]} EqV' [gamma] [phi] [phi |- #T] [gamma |- #p] [phi |- #q.1] +-> ExistsEq' [gamma] [phi] [phi |- #T ] [phi |- #q.1] ; -rec existsEqV' : Ctx_xdR [gamma] [phi] [phi |- #T[..]] -> {#p: [phi |- block (x:tm, u:deq x x) ]} - ExistsEq' [gamma] [phi] [phi |- #T[..]] [phi |- #p.1[..]] = -fn cr_xd => mlam #p => let (cr_xd : Ctx_xdR [gamma] [phi] [phi |- #T[..] ] ) = cr_xd in -case [phi |- #p.1[..]] of +rec existsEqV' : Ctx_xdR [gamma] [phi] [phi |- #T] -> {#p: [phi |- block (x:tm, u:deq x x) ]} + ExistsEq' [gamma] [phi] [phi |- #T] [phi |- #p.1] = +fn cr_xd => mlam #p => let (cr_xd : Ctx_xdR [gamma] [phi] [phi |- #T ] ) = cr_xd in +case [phi |- #p.1] of | [phi, b:block (x:tm, u:deq x x) |- b.1] => let Cons_xd cr'_xd = cr_xd in - let (cr'_xd : Ctx_xdR [gamma] [phi] [phi |- #T[..] ]) = cr'_xd in + let (cr'_xd : Ctx_xdR [gamma] [phi] [phi |- #T ]) = cr'_xd in ExistsEqV' [gamma,x:tm |- x ] EqV'_v | [phi, b:block (x:tm, u:deq x x) |- #p.1[..]] => let Cons_xd cr'_xd = cr_xd in - let ExistsEqV' [gamma |- #r[..]] eq = existsEqV' cr'_xd [phi |- #p[..]] in + let ExistsEqV' [gamma |- #r] eq = existsEqV' cr'_xd [phi |- #p] in ExistsEqV' [gamma,x:tm |- #r[..]] (EqV'_p eq) ; -rec existsEq' : Ctx_xdR [gamma] [phi] [phi |- #T[..]] -> {Ld: [phi |- tm]} - ExistsEq' [gamma] [phi] [phi |- #T[..]] [phi |- Ld] = -fn cr_xd => mlam Ld => let (cr_xd : Ctx_xdR [gamma] [phi] [phi |- #T[..] ] ) = cr_xd in -case [phi |- Ld[..]] of -| [phi |- #p.1[..]] => existsEqV' cr_xd [phi |- #p[..]] +rec existsEq' : Ctx_xdR [gamma] [phi] [phi |- #T] -> {Ld: [phi |- tm]} + ExistsEq' [gamma] [phi] [phi |- #T] [phi |- Ld] = +fn cr_xd => mlam Ld => let (cr_xd : Ctx_xdR [gamma] [phi] [phi |- #T ] ) = cr_xd in +case [phi |- Ld] of +| [phi |- #p.1] => existsEqV' cr_xd [phi |- #p] -| [phi |- app (M[..]) (N[..]) ] => - let ExistsEq' [gamma |- L1[..]] eq1 = existsEq' cr_xd [phi |- M[..]] in - let ExistsEq' [gamma |- L2[..]] eq2 = existsEq' cr_xd [phi |- N[..]] in - ExistsEq' [gamma |- app (L1[..]) (L2[..])] (Eq'_a eq1 eq2) +| [phi |- app M N ] => + let ExistsEq' [gamma |- L1] eq1 = existsEq' cr_xd [phi |- M] in + let ExistsEq' [gamma |- L2] eq2 = existsEq' cr_xd [phi |- N] in + ExistsEq' [gamma |- app (L1) (L2)] (Eq'_a eq1 eq2) | [phi |- lam \x. M] => let ExistsEq' [gamma, x:tm |- L] eq = @@ -326,46 +328,46 @@ case [phi |- Ld[..]] of % forall L given Ctx_xaR [gamma] [psi] [psi |- #S..[]], -% there exists an La s.t. Eq [gamma] [psi] [psi |- #S..[]] [gamma |- L[..]] [psi |- La[..]] +% there exists an La s.t. Eq [gamma] [psi] [psi |- #S..[]] [gamma |- L] [psi |- La] inductive ExistsEq : {gamma:xG}{psi: xaG}{#S : [psi |- gamma]} {L: [gamma |- tm]} ctype = | ExistsEqV : - {La:[psi |- tm]} EqV [gamma] [psi] [psi |- #S[..]] [gamma |- #p] [psi |- #q.1] - -> ExistsEq [gamma] [psi] [psi |- #S[..] ] [gamma |- #p[..]] + {La:[psi |- tm]} EqV [gamma] [psi] [psi |- #S] [gamma |- #p] [psi |- #q.1] + -> ExistsEq [gamma] [psi] [psi |- #S ] [gamma |- #p] | ExistsEq : - {La:[psi |- tm]} Eq [gamma] [psi] [psi |- #S[..]] [gamma |- L] [psi |- La[..]] --> ExistsEq [gamma] [psi] [psi |- #S[..] ] [gamma |- L[..]] + {La:[psi |- tm]} Eq [gamma] [psi] [psi |- #S] [gamma |- L] [psi |- La] +-> ExistsEq [gamma] [psi] [psi |- #S ] [gamma |- L] ; -rec existsEqV : Ctx_xaR [gamma] [psi] [psi |- #S[..]] -> {#p: [gamma |- tm]} - ExistsEq [gamma] [psi] [psi |- #S[..]] [gamma |- #p[..]] = -fn cr_xa => mlam #p => let (cr_xa : Ctx_xaR [gamma] [psi] [psi |- #S[..] ] ) = cr_xa in -case [gamma |- #p[..]] of +rec existsEqV : Ctx_xaR [gamma] [psi] [psi |- #S] -> {#p: [gamma |- tm]} + ExistsEq [gamma] [psi] [psi |- #S] [gamma |- #p] = +fn cr_xa => mlam #p => let (cr_xa : Ctx_xaR [gamma] [psi] [psi |- #S ] ) = cr_xa in +case [gamma |- #p] of | [gamma, x:tm |- x] => let Cons_xa cr'_xa = cr_xa in - let (cr'_xa : Ctx_xaR [gamma] [psi] [psi |- #S[..] ]) = cr'_xa in + let (cr'_xa : Ctx_xaR [gamma] [psi] [psi |- #S ]) = cr'_xa in ExistsEqV [psi,b:block (x:tm,u:aeq x x) |- b.1 ] EqV_v | [gamma, x:tm |- #p[..]] => let Cons_xa cr'_xa = cr_xa in - let ExistsEqV [psi |- #q.1[..]] eq = existsEqV cr'_xa [gamma |- #p[..]] in - let (eq : EqV [gamma] [psi] [psi |- #S[..] ] [gamma |- #p[..]][psi |- #q.1[..]]) = eq in + let ExistsEqV [psi |- #q.1] eq = existsEqV cr'_xa [gamma |- #p] in + let (eq : EqV [gamma] [psi] [psi |- #S ] [gamma |- #p][psi |- #q.1]) = eq in ExistsEqV [psi,b:block (x:tm,u:aeq x x) |- #q.1[..]] (EqV_p eq) ; -rec existsEq : Ctx_xaR [gamma] [psi] [psi |- #S[..]] -> {L: [gamma |- tm]} - ExistsEq [gamma] [psi] [psi |- #S[..]] [gamma |- L[..]] = +rec existsEq : Ctx_xaR [gamma] [psi] [psi |- #S] -> {L: [gamma |- tm]} + ExistsEq [gamma] [psi] [psi |- #S] [gamma |- L] = -fn cr_xa => mlam L => let (cr_xa : Ctx_xaR [gamma] [psi] [psi |- #S[..] ] ) = cr_xa in -case [gamma |- L[..]] of -| [gamma |- #p[..]] => existsEqV cr_xa [gamma |- #p[..]] +fn cr_xa => mlam L => let (cr_xa : Ctx_xaR [gamma] [psi] [psi |- #S ] ) = cr_xa in +case [gamma |- L] of +| [gamma |- #p] => existsEqV cr_xa [gamma |- #p] -| [gamma |- app (M[..]) (N[..])] => - let ExistsEq [psi |- La1[..]] eq1 = existsEq cr_xa [gamma |- M[..]] in - let ExistsEq [psi |- La2[..]] eq2 = existsEq cr_xa [gamma |- N[..]] in - ExistsEq [psi |- app (La1[..]) (La2[..])] (Eq_a eq1 eq2) +| [gamma |- app M N] => + let ExistsEq [psi |- La1] eq1 = existsEq cr_xa [gamma |- M] in + let ExistsEq [psi |- La2] eq2 = existsEq cr_xa [gamma |- N] in + ExistsEq [psi |- app (La1) (La2)] (Eq_a eq1 eq2) | [gamma |- lam \x. M] => let ExistsEq [psi, b:block (x:tm, u:aeq x x) |- La[..,b.1]] eq = @@ -373,9 +375,9 @@ case [gamma |- L[..]] of ExistsEq [psi |- lam \x. La] (Eq_l eq) ; -rec det_eqV : EqV [gamma] [psi] [psi |- #S[..] ] [gamma |- #p[..]] [psi |- #q.1[..]] -> - EqV [gamma] [psi] [psi |- #S[..] ] [gamma |- #p[..]] [psi |- #r.1[..]] -> - Equal_xaG [psi |- #q.1[..]] [psi |- #r.1[..]] = +rec det_eqV : EqV [gamma] [psi] [psi |- #S ] [gamma |- #p] [psi |- #q.1] -> + EqV [gamma] [psi] [psi |- #S ] [gamma |- #p] [psi |- #r.1] -> + Equal_xaG [psi |- #q.1] [psi |- #r.1] = fn v => fn v' => case v of | EqV_v => let EqV_v = v' in Refl_xaG | EqV_p v => @@ -384,9 +386,9 @@ fn v => fn v' => case v of ; rec det_eq : - Eq [gamma] [psi] [psi |- #S[..] ] [gamma |- M[..]] [psi |- N[..]] -> - Eq [gamma] [psi] [psi |- #S[..] ] [gamma |- M[..]] [psi |- N'[..]] -> - Equal_xaG [psi |- N[..]] [psi |- N'[..]] = + Eq [gamma] [psi] [psi |- #S ] [gamma |- M] [psi |- N] -> + Eq [gamma] [psi] [psi |- #S ] [gamma |- M] [psi |- N'] -> + Equal_xaG [psi |- N] [psi |- N'] = fn m => fn m' => case m of | Eq_v v => let Eq_v v' = m' in det_eqV v v' | Eq_a m1 m2 => @@ -400,9 +402,9 @@ fn m => fn m' => case m of Refl_xaG ; -rec det_eqV' : EqV' [gamma] [psi] [psi |- #S[..] ] [gamma |- #q[..]] [psi |- #p.1[..]] -> - EqV' [gamma] [psi] [psi |- #S[..] ] [gamma |- #r[..]] [psi |- #p.1[..]] -> - Equal_xG [gamma |- #q[..]] [gamma |- #r[..]] = +rec det_eqV' : EqV' [gamma] [psi] [psi |- #S ] [gamma |- #q] [psi |- #p.1] -> + EqV' [gamma] [psi] [psi |- #S ] [gamma |- #r] [psi |- #p.1] -> + Equal_xG [gamma |- #q] [gamma |- #r] = fn v => fn v' => case v of | EqV'_v => let EqV'_v = v' in Refl_xG | EqV'_p v => @@ -410,9 +412,9 @@ fn v => fn v' => case v of let Refl_xG = det_eqV' v v' in Refl_xG ; rec det_eq' : - Eq' [gamma] [psi] [psi |- #S[..] ] [gamma |- M[..]] [psi |- N[..]] -> - Eq' [gamma] [psi] [psi |- #S[..] ] [gamma |- M'[..]] [psi |- N[..]] -> - Equal_xG [gamma |- M[..]] [gamma |- M'[..]] = + Eq' [gamma] [psi] [psi |- #S ] [gamma |- M] [psi |- N] -> + Eq' [gamma] [psi] [psi |- #S ] [gamma |- M'] [psi |- N] -> + Equal_xG [gamma |- M] [gamma |- M'] = fn m => fn m' => case m of | Eq'_v v => let Eq'_v v' = m' in det_eqV' v v' | Eq'_a m1 m2 => @@ -430,49 +432,49 @@ fn m => fn m' => case m of % --------------------------------------------------------------------------- -rec ceq: Ctx_xaR [gamma] [psi] [psi |- #S[..] ] -> - Ctx_xdR [gamma] [phi] [phi |- #T[..] ] -> +rec ceq: Ctx_xaR [gamma] [psi] [psi |- #S ] -> + Ctx_xdR [gamma] [phi] [phi |- #T ] -> Ctx_adR [psi] [phi] -> - Eq [gamma] [psi] [psi |- #S[..] ] [gamma |- M[..]] [psi |- Ma[..]] -> - Eq [gamma] [psi] [psi |- #S[..] ] [gamma |- N[..]] [psi |- Na[..]] -> - Eq' [gamma] [phi] [phi |- #T[..] ] [gamma |- M[..]] [phi |- Md[..]] -> - Eq' [gamma] [phi] [phi |- #T[..] ] [gamma |- N[..]] [phi |- Nd[..]] -> - [phi |- deq (Md[..]) (Nd[..])] -> [psi |- aeq (Ma[..]) (Na[..])] = + Eq [gamma] [psi] [psi |- #S ] [gamma |- M] [psi |- Ma] -> + Eq [gamma] [psi] [psi |- #S ] [gamma |- N] [psi |- Na] -> + Eq' [gamma] [phi] [phi |- #T ] [gamma |- M] [phi |- Md] -> + Eq' [gamma] [phi] [phi |- #T ] [gamma |- N] [phi |- Nd] -> + [phi |- deq Md Nd] -> [psi |- aeq Ma Na] = fn cr_a => fn cr_d => fn cr_da => fn ma => fn na => fn md => fn nd => fn d => let (cr_da : Ctx_adR [psi] [phi]) = cr_da in -let (cr_a : Ctx_xaR [gamma] [psi] [psi |- #S[..]]) = cr_a in +let (cr_a : Ctx_xaR [gamma] [psi] [psi |- #S]) = cr_a in case d of - | [phi |- #p.2[..]] => + | [phi |- #p.2] => let Refl_xG = det_eq' md nd in let Refl_xaG = det_eq ma na in let Eq'_v v' = md in let Eq_v v = ma in - let (v : EqV [gamma] [psi] [psi |- #S[..]] [gamma |- #r[..] ] [psi |- #q.1[..]]) = v in - ctx_member [gamma |- #r[..]] cr_a v + let (v : EqV [gamma] [psi] [psi |- #S] [gamma |- #r ] [psi |- #q.1]) = v in + ctx_member [gamma |- #r] cr_a v | [phi |- de_r ] => let Refl_xG = det_eq' md nd in let Refl_xaG = det_eq ma na in reflR [gamma] [gamma |- _ ] cr_a ma -| [phi |- de_t (D1[..]) (D2[..])] => - let ([phi |- D1[..] ] : [phi |- deq (Md[..]) (Ld[..])]) = [phi |- D1[..]] in - let ([phi |- D2[..] ] : [phi |- deq (Ld[..]) (Nd[..])]) = [phi |- D2[..]] in - let ExistsEq' [gamma |- L[..]] ld = existsEq' cr_d [phi |- Ld[..]] in - let ExistsEq [psi |- La[..]] la = existsEq cr_a [gamma |- L[..]] in - let [psi |- E1[..] ] = ceq cr_a cr_d cr_da ma la md ld [phi |- D1[..]] in - let [psi |- E2[..] ] = ceq cr_a cr_d cr_da la na ld nd [phi |- D2[..]] in - transR cr_a ma la na [psi |- E1[..]] [psi |- E2[..]] +| [phi |- de_t D1 D2] => + let ([phi |- D1 ] : [phi |- deq Md Ld]) = [phi |- D1] in + let ([phi |- D2 ] : [phi |- deq Ld Nd]) = [phi |- D2] in + let ExistsEq' [gamma |- L] ld = existsEq' cr_d [phi |- Ld] in + let ExistsEq [psi |- La] la = existsEq cr_a [gamma |- L] in + let [psi |- E1 ] = ceq cr_a cr_d cr_da ma la md ld [phi |- D1] in + let [psi |- E2 ] = ceq cr_a cr_d cr_da la na ld nd [phi |- D2] in + transR cr_a ma la na [psi |- E1] [psi |- E2] -| [phi |- de_a (D1[..]) (D2[..])] => +| [phi |- de_a D1 D2] => let Eq_a ma1 ma2 = ma in let Eq'_a md1 md2 = md in let Eq_a na1 na2 = na in let Eq'_a nd1 nd2 = nd in - let [psi |- E1[..]] = ceq cr_a cr_d cr_da ma1 na1 md1 nd1 [phi |- D1[..]] in - let [psi |- E2[..]] = ceq cr_a cr_d cr_da ma2 na2 md2 nd2 [phi |- D2[..]] in - [psi |- ae_a (E1[..]) (E2[..])] + let [psi |- E1] = ceq cr_a cr_d cr_da ma1 na1 md1 nd1 [phi |- D1] in + let [psi |- E2] = ceq cr_a cr_d cr_da ma2 na2 md2 nd2 [phi |- D2] in + [psi |- ae_a E1 E2] | [phi |- de_l \x.\u. D] => let Eq_l ma1 = ma in diff --git a/examples/literate_beluga/0Beginner/Untyped_Algorithmic_Equality_-_Context_Subsumption.bel b/examples/literate_beluga/0Beginner/Untyped_Algorithmic_Equality_-_Context_Subsumption.bel index 3b5c58c40..e339c9be3 100755 --- a/examples/literate_beluga/0Beginner/Untyped_Algorithmic_Equality_-_Context_Subsumption.bel +++ b/examples/literate_beluga/0Beginner/Untyped_Algorithmic_Equality_-_Context_Subsumption.bel @@ -61,48 +61,48 @@ schema xaG = block x:tm, ae_v:aeq x x; schema daG = block (x: tm, ae_v:aeq x x, de_v:deq x x) ; %{{ ## Proof of Reflexivity -We first prove admissibility of reflexivity. The proof is implemented as a recursive function called reflG of type {g:xaG}{M:[g |- tm ]}[g |- aeq (M[..])(M[..])]: for all contexts g that have schema xaG, for all terms M, we have a proof that [g |- aeq (M[..])(M[..])]. Quantification over contexts and contextual objects in computation-level types is denoted by curly braces; the corresponding abstraction on the level of expressions is written as mlam g => mlam M => e.}}% -rec reflG: {g:xaG} {M:[g |- tm]} [g |- aeq (M[..]) (M[..])] = -mlam g => mlam M => case [g |- (M[..])] of -| [g |- #p.1[..]] => [g |- #p.2[..]] -| [g |- lam \x. M] => - let [g,b:block y:tm, ae_v:aeq y y |- D[..,b.1,b.2]] = - reflG [g, b:block y:tm, ae_v:aeq y y] [g, b |- M[..,b.1]] +We first prove admissibility of reflexivity. The proof is implemented as a recursive function called reflG of type {g:xaG}{M:[gamma |- tm ]}[gamma |- aeq M M]: for all contexts g that have schema xaG, for all terms M, we have a proof that [gamma |- aeq M M]. Quantification over contexts and contextual objects in computation-level types is denoted by curly braces; the corresponding abstraction on the level of expressions is written as mlam g => mlam M => e.}}% +rec reflG: {gamma:xaG} {M:[gamma |- tm]} [gamma |- aeq M M] = +mlam gamma => mlam M => case [gamma |- M] of +| [gamma |- #p.1] => [gamma |- #p.2] +| [gamma |- lam \x. M] => + let [gamma,b:block y:tm, ae_v:aeq y y |- D[..,b.1,b.2]] = + reflG [gamma, b:block y:tm, ae_v:aeq y y] [gamma, b |- M[..,b.1]] in - [g |- ae_l \x. \w. D] % : eq (L) (L) -| [g |- app (M1[..]) (M2[..])] => - let [g |- D1[..]] = reflG [g] [g |- M1[..] ] in - let [g |- D2[..]] = reflG [g] [g |- M2[..] ] in - [g |- ae_a (D1[..]) (D2[..])] + [gamma |- ae_l \x. \w. D] % : eq L L +| [gamma |- app M1 M2] => + let [gamma |- D1] = reflG [gamma] [gamma |- M1 ] in + let [gamma |- D2] = reflG [gamma] [gamma |- M2 ] in + [gamma |- ae_a D1 D2] ; -%{{In the proof for reflG we begin by introducing and M followed by a case analysis on [g |- M[..]] using pattern matching. There are three possible cases for M: +%{{In the proof for reflG we begin by introducing and M followed by a case analysis on [gamma |- M] using pattern matching. There are three possible cases for M: }}% % --------------------------------------------------------------------------- % General transitivity is admissible %{{## Proof of Transitivity -Next, we prove admissibility of transitivity. We encode the proof of transitivity by pattern-matching on the first derivation [g |- aeq (M[..]) (L[..])] to arrive at the second [g |- aeq (L[..]) (N[..])]. The recursive function transG handles the three cases for variables, lambda-terms, and applications in a similar fashion to reflG}. The context g:xaG is surrounded by parentheses ( ) to indicate that it is implicit in the actual proof and need to be reconstructed. }}% -rec transG: (g:xaG) - [g |- aeq (M[..]) (L[..])] -> [g |- aeq (L[..]) (N[..])] - -> [g |- aeq (M[..]) (N[..])] = +Next, we prove admissibility of transitivity. We encode the proof of transitivity by pattern-matching on the first derivation [gamma |- aeq M L] to arrive at the second [gamma |- aeq L N]. The recursive function transG handles the three cases for variables, lambda-terms, and applications in a similar fashion to reflG}. The context g:xaG is surrounded by parentheses ( ) to indicate that it is implicit in the actual proof and need to be reconstructed. }}% +rec transG: (gamma:xaG) + [gamma |- aeq M L] -> [gamma |- aeq L N] + -> [gamma |- aeq M N] = fn d1 => fn d2 => case d1 of -| [g |- #p.2[..]] => d2 -| [g |- ae_l \x.\u. D1] => - let [g |- ae_l \x.\u. D2] = d2 in - let [g, b:block x:tm, ae_v:aeq x x |- E[..,b.1,b.2]] = - transG [g, b:block x':tm, ae_v:aeq x' x' |- D1[..,b.1,b.2]] - [g, b |- D2[..,b.1,b.2]] +| [gamma |- #p.2] => d2 +| [gamma |- ae_l \x.\u. D1] => + let [gamma |- ae_l \x.\u. D2] = d2 in + let [gamma, b:block x:tm, ae_v:aeq x x |- E[..,b.1,b.2]] = + transG [gamma, b:block x':tm, ae_v:aeq x' x' |- D1[..,b.1,b.2]] + [gamma, b |- D2[..,b.1,b.2]] in - [g |- ae_l \x. \u. E] -| [g |- ae_a (D1[..]) (D2[..])] => - let [g |- ae_a (F1[..]) (F2[..])] = d2 in - let [g |- E1[..]] = transG [g |- D1[..]] [g |- F1[..]] in - let [g |- E2[..]] = transG [g |- D2[..]] [g |- F2[..]] in - [g |- ae_a (E1[..]) (E2[..])] + [gamma |- ae_l \x. \u. E] +| [gamma |- ae_a D1 D2] => + let [gamma |- ae_a F1 F2] = d2 in + let [gamma |- E1] = transG [gamma |- D1] [gamma |- F1] in + let [gamma |- E2] = transG [gamma |- D2] [gamma |- F2] in + [gamma |- ae_a E1 E2] ; %{{Here, the variable case exploits that if aeq M N is an element of the context g, then M = N. Note that the recursive calls do not take the context g as an explicit argument.}}% @@ -112,19 +112,19 @@ fn d1 => fn d2 => case d1 of ## Proof of Symmetry Again, we encode the proof of symmetry as a recursive function symG. As in transG, the context g is implicit. Furthermore, we handle the variable case using the same property in both functions. }}% -rec symG: (g:xaG) - [g |- aeq (M[..]) (L[..])] -> [g |- aeq (L[..]) (M[..])] = +rec symG: (gamma:xaG) + [gamma |- aeq M L] -> [gamma |- aeq L M] = fn d => case d of -| [g |- #p.2[..]] => d -| [g |- ae_l \x.\u. D1] => - let [g, b:block x:tm, ae_v:aeq x x |- E[..,b.1,b.2]] = - symG [g, b:block x':tm, ae_v:aeq x' x' |- D1[..,b.1,b.2]] +| [gamma |- #p.2] => d +| [gamma |- ae_l \x.\u. D1] => + let [gamma, b:block x:tm, ae_v:aeq x x |- E[..,b.1,b.2]] = + symG [gamma, b:block x':tm, ae_v:aeq x' x' |- D1[..,b.1,b.2]] in - [g |- ae_l \x. \u. E] -| [g |- ae_a (D1[..]) (D2[..])] => - let [g |- E1[..]] = symG [g |- D1[..]] in - let [g |- E2[..]] = symG [g |- D2[..]] in - [g |- ae_a (E1[..]) (E2[..])] + [gamma |- ae_l \x. \u. E] +| [gamma |- ae_a D1 D2] => + let [gamma |- E1] = symG [gamma |- D1] in + let [gamma |- E2] = symG [gamma |- D2] in + [gamma |- ae_a E1 E2] ; % --------------------------------------------------------------------------- @@ -132,31 +132,31 @@ fn d => case d of ## Proof of Completeness Finally, we implement the completeness proof as as a recursive function ceqG. }}% -rec ceq: (g:daG) [g |- deq (M[..]) (N[..])] -> [g |- aeq (M[..]) (N[..])] = +rec ceq: (gamma:daG) [gamma |- deq M N] -> [gamma |- aeq M N] = fn e => case e of -| [g |- #p.3[..]] => [g |- #p.2[..]] -| [g |- de_r] => reflG [g] [g |- _ ] -| [g |- de_a (D1[..]) (D2[..])] => - let [g |- F1[..]] = ceq [g |- D1[..]] in - let [g |- F2[..]] = ceq [g |- D2[..]] in - [g |- ae_a (F1[..]) (F2[..])] -| [g |- de_l (\x.(\u. D))] => - let [g,b:block x:tm, _t:aeq x x, u:deq x x |- F[..,b.1,b.2]] = - ceq [g, b:block x:tm, _t:aeq x x, u:deq x x |- D[..,b.1,b.3]] +| [gamma |- #p.3] => [gamma |- #p.2] +| [gamma |- de_r] => reflG [gamma] [gamma |- _ ] +| [gamma |- de_a D1 D2] => + let [gamma |- F1] = ceq [gamma |- D1] in + let [gamma |- F2] = ceq [gamma |- D2] in + [gamma |- ae_a F1 F2] +| [gamma |- de_l (\x.\u. D)] => + let [gamma,b:block x:tm, _t:aeq x x, u:deq x x |- F[..,b.1,b.2]] = + ceq [gamma, b:block x:tm, _t:aeq x x, u:deq x x |- D[..,b.1,b.3]] in - [g |- ae_l (\x.\v. F)] -| [g |- de_t (D1[..]) (D2[..])] => - let [g |- F2[..]] = ceq [g |- D2[..]] in - let [g |- F1[..]] = ceq [g |- D1[..]] in - transG [g |- F1[..]] [g |- F2[..]] -| [g |- de_s (D[..])] => - let [g |- F[..]] = ceq [g |- D[..]] in - symG [g |- F[..]] + [gamma |- ae_l (\x.\v. F)] +| [gamma |- de_t D1 D2] => + let [gamma |- F2] = ceq [gamma |- D2] in + let [gamma |- F1] = ceq [gamma |- D1] in + transG [gamma |- F1] [gamma |- F2] +| [gamma |- de_s D] => + let [gamma |- F] = ceq [gamma |- D] in + symG [gamma |- F] ; %{{ -

We explain here the three cases shown in the informal proof in the companion paper (Felty et al, 2014). First, let us consider the case where we used an assumption from the context. Since the context g consists of blocks with the following structure: block x:tm , ae_v:aeq x x,de_v: deq x x, we in fact want to match on the third element of such a block. This is written as #p.3[..]. The type of #p.3 is deq (#p.1[..]) (#p.1[..]). Since our context always contains a block and the parameter variable #p[..] describes such a block, we know that there exists a proof for aeq (#p.1[..]) (#p.1[..]), which can be described by #p.2[..].

+

We explain here the three cases shown in the informal proof in the companion paper (Felty et al, 2014). First, let us consider the case where we used an assumption from the context. Since the context g consists of blocks with the following structure: block x:tm , ae_v:aeq x x,de_v: deq x x, we in fact want to match on the third element of such a block. This is written as #p.3. The type of #p.3 is deq #p.1 #p.1. Since our context always contains a block and the parameter variable #p describes such a block, we know that there exists a proof for aeq #p.1 #p.1, which can be described by #p.2.



Second, we consider the case where we applied the reflexivity rule de_r as a last step. In this case, we need to refer to the reflexivity lemma we proved about algorithmic equality. To use the function reflG, which implements the reflexivity lemma for algorithmic equality, we need a context of schema xaG; however, the context used in the proof for ceqG is of schema daG and we rely on context subsumption to justify passing a context daG in place of a context xaG. The cases for transitivity and symmetry are similar.

-

Third, we consider the case for de_l, the case for lambda-abstractions. In this case, we extend the context with the new declarations about variables and pass to the recursive call ceqG the derivation [g, b:block (x:tm ,ae_v:aeq x x, de_v: deq x x) |- D[..] b.1 b.3]. Declaration weakening (in the informal proof d-wk (Felty et al, 2014)) is built-in. In the pattern, the derivation D has type [g, x:tm , ae_v:aeq x x |- deq (M[..]x)(N)]. We hence construct a weakening substitution .. b.1 b.3 that allows us to move D to the context g, b:block (x:tm,ae_v:aeq x x, de_v:deq x x). The result of recursive call is a derivation F, where F only depends on x:tm and u:aeq x x. In the on-paper proof we refer to declaration strengthening (d-str) to justify that F cannot depend on de_v assumptions. In Beluga, the programmer uses strengthening by stating which assumptions F can depend on. The coverage checker will then subsequently rely on subordination to verify that the restricted case is sufficient and no other cases have been forgotten. Subordination allows us to verify that indeed assumptions of type de_v: deq x x cannot be used in proofs for aeq (M[..] b.1) (N[..] b.1). Finally, we use F to assemble the final result ae_l (\x.\v. F v).

+

Third, we consider the case for de_l, the case for lambda-abstractions. In this case, we extend the context with the new declarations about variables and pass to the recursive call ceqG the derivation [gamma, b:block (x:tm ,ae_v:aeq x x, de_v: deq x x) |- D[..,b.1, b.3]]. Declaration weakening (in the informal proof d-wk (Felty et al, 2014)) is built-in. In the pattern, the derivation D has type [gamma, x:tm , ae_v:aeq x x |- deq M[..,x] N]. We hence construct a weakening substitution .. b.1 b.3 that allows us to move D to the context gamma, b:block (x:tm,ae_v:aeq x x, de_v:deq x x). The result of recursive call is a derivation F, where F only depends on x:tm and u:aeq x x. In the on-paper proof we refer to declaration strengthening (d-str) to justify that F cannot depend on de_v assumptions. In Beluga, the programmer uses strengthening by stating which assumptions F can depend on. The coverage checker will then subsequently rely on subordination to verify that the restricted case is sufficient and no other cases have been forgotten. Subordination allows us to verify that indeed assumptions of type de_v: deq x x cannot be used in proofs for aeq M[.., b.1] N[.., b.1]. Finally, we use F to assemble the final result ae_l (\x.\v. F).



We conclude this example with a few observations: The statement of the theorem is directly and succinctly represented in Beluga using contextual types and contextual objects. Every case in the on-paper proof corresponds directly to a case in the implementation of the recursive function. Type reconstruction is used to reconstruct implicit type arguments and infer the type of free contextual variables that occur in patterns. This is crucial to achieve a palatable source language. Weakening and strengthening are supported in Beluga through the typing rules and on the level of context variables and context schemas using context subsumption. If schema W is a prefix of a schema W', then we can always use a context of schema W' in place of a context of schema W.

}}% diff --git a/src/core/html.ml b/src/core/html.ml index 2d21609e3..c3543416f 100644 --- a/src/core/html.ml +++ b/src/core/html.ml @@ -51,6 +51,10 @@ let generatePage orig = let page = Str.global_replace (Str.regexp_string "..") "…" page in let page = Str.global_replace (Str.regexp_string "->") "→" page in let page = Str.global_replace (Str.regexp_string "=>") "⇒" page in + let page = Str.global_replace (Str.regexp_string "#S") "σ" page in + let page = Str.global_replace (Str.regexp_string "phi") "φ" page in + let page = Str.global_replace (Str.regexp_string "psi") "ψ" page in + let page = Str.global_replace (Str.regexp_string "gamma") "γ" page in let page = Str.global_replace (Str.regexp "\\\\\\([a-z][a-z0-9]*\\.\\)") "λ\\1" page in (* Output the HTML file *) let oc = open_out !filename in @@ -128,4 +132,4 @@ let idExists s = List.exists (fun x -> x=s) !ids let arrow = '→' -let arrow2 = '⇒'*) \ No newline at end of file +let arrow2 = '⇒'*) diff --git a/src/core/prettyext.ml b/src/core/prettyext.ml index 715289204..62a8af790 100644 --- a/src/core/prettyext.ml +++ b/src/core/prettyext.ml @@ -255,6 +255,15 @@ module Ext = struct (to_html "block" Keyword) (fmt_ppr_lf_typ_rec cD cPsi lvl) typRec + | LF.ArrTyp (_, (LF.PiTyp _ as t1), t2) -> + let cond = lvl > 1 in + fprintf ppf "%s%a %s %a%s" + (l_paren_if cond) + (fmt_ppr_lf_typ cD cPsi 2) t1 + (symbol_to_html RArr) + (fmt_ppr_lf_typ cD cPsi 0) t2 + (r_paren_if cond) + | LF.ArrTyp (_, (LF.ArrTyp _ as t1), t2) -> let cond = lvl > 1 in fprintf ppf "%s%a %s %a%s" @@ -346,7 +355,7 @@ module Ext = struct let paren s = not (Control.db()) && lvl > 0 && true in begin match head with | LF.MVar (_, x, LF.EmptySub _) -> - fprintf ppf "%s[^]" (Id.render_name x) + fprintf ppf "%s[]" (Id.render_name x) | LF.MVar (_, x, s) -> fprintf ppf "%s%a" (Id.render_name x) @@ -373,10 +382,16 @@ module Ext = struct | LF.Hole (_) -> fprintf ppf "_" - | LF.Proj (_, h, p) -> + | LF.Proj (_, (LF.Name _ as h), p) -> fprintf ppf "%a.%a" (fmt_ppr_lf_head cD cPsi lvl) h (fmt_ppr_lf_proj lvl) p + + | LF.Proj (_, LF.PVar (_, x, s), p) -> + fprintf ppf "#%s.%a%a" + (Id.render_name x) + (fmt_ppr_lf_proj lvl) p + (fmt_ppr_lf_sub cD cPsi lvl) s end and fmt_ppr_lf_proj lvl ppf = function | LF.ByName n -> fprintf ppf "%s" (Id.render_name n) @@ -396,13 +411,15 @@ module Ext = struct | Control.Natural -> fmt_ppr_lf_sub_natural cD cPsi lvl ppf s | Control.DeBruijn -> fmt_ppr_lf_sub_deBruijn cD cPsi lvl ppf s - and fmt_ppr_lf_sub_natural cD cPsi lvl ppf s = + and fmt_ppr_lf_sub_bare cD cPsi lvl ppf s = + match !Control.substitutionStyle with + | Control.Natural -> fmt_ppr_lf_sub_natural_bare cD cPsi lvl ppf s + | Control.DeBruijn -> fmt_ppr_lf_sub_deBruijn_bare cD cPsi lvl ppf s + + and fmt_ppr_lf_sub_natural_bare cD cPsi lvl ppf s = let print_front = fmt_ppr_lf_front cD cPsi 1 in - let hasCtxVar = has_ctx_var cPsi in - let rec self lvl ppf = (function - (* Print ".." for a Shift when there is a context variable present, - and nothing otherwise *) - (* above is WRONG *) + let hasCtxVar = has_ctx_var cPsi in + let rec self lvl ppf s = match s with | LF.Dot (_, f, s) when hasCtxVar -> fprintf ppf "%a, %a" (self lvl) f print_front s @@ -415,25 +432,34 @@ module Ext = struct | LF.Id _ -> fprintf ppf "%s" (symbol_to_html Dots) - | LF.RealId -> () + | LF.RealId -> () (* fprintf ppf "%s" (symbol_to_html Dots) *) | LF.EmptySub _ -> fprintf ppf "" | LF.SVar(_, s, LF.EmptySub _) -> fprintf ppf "#%s[^]" (Id.render_name s) + | LF.SVar(_, s, LF.RealId) -> + fprintf ppf "#%s" + (Id.render_name s) | LF.SVar (_, s, f) -> fprintf ppf "#%s[%a]" (Id.render_name s) - (self lvl) f) - in + (self lvl) f + in + self lvl ppf s + + and fmt_ppr_lf_sub_natural cD cPsi lvl ppf s = (match s with | LF.RealId -> fprintf ppf "" - | _ -> fprintf ppf "[%a]" (self lvl) s) + | _ -> fprintf ppf "[%a]" (fmt_ppr_lf_sub_natural_bare cD cPsi lvl) s) and fmt_ppr_lf_sub_deBruijn cD cPsi lvl ppf s = - let rec self lvl ppf = function + fprintf ppf "[%a]" + (fmt_ppr_lf_sub_deBruijn_bare cD cPsi lvl) s + and fmt_ppr_lf_sub_deBruijn_bare cD cPsi lvl ppf s = + let rec self lvl ppf = function | LF.Id _ -> fprintf ppf "%s" (symbol_to_html Dots) @@ -445,8 +471,7 @@ module Ext = struct (fmt_ppr_lf_front cD cPsi 1) f (self lvl) s in - fprintf ppf "[%a]" - (self lvl) s + self lvl ppf s and fmt_ppr_lf_front cD cPsi lvl ppf = function @@ -692,7 +717,7 @@ module Ext = struct fprintf ppf "[%a %s %a]" (fmt_ppr_lf_dctx cD 0) cPsi (symbol_to_html Turnstile) - (fmt_ppr_lf_sub cD cPsi 0) sigma + (fmt_ppr_lf_sub_bare cD cPsi 0) sigma | Comp.ClObj (cPsi, Comp.PObj h) -> fprintf ppf "[%a %s %a]" (fmt_ppr_lf_psi_hat cD 0) cPsi @@ -701,12 +726,10 @@ module Ext = struct let rec fmt_ppr_cmp_typ cD lvl ppf = function | Comp.TypBase (_, x, mS)-> - let cond = lvl > 1 in - fprintf ppf "%s%s%a%s" - (l_paren_if cond) + fprintf ppf "%s%a" (to_html (Id.render_name x) Link) (fmt_ppr_meta_spine cD 0) mS - (r_paren_if cond) + | Comp.TypBox (_, (_,LF.ClTyp (LF.MTyp tA, cPsi))) -> fprintf ppf "[%a %s %a]" @@ -935,7 +958,7 @@ module Ext = struct | Comp.BoxVal (_, m0) -> let cond = lvl > 1 in - fprintf ppf "%s[%a]%s" + fprintf ppf "%s%a%s" (l_paren_if cond) (fmt_ppr_meta_obj cD 0) m0 (r_paren_if cond)