|
| 1 | +/- |
| 2 | +Copyright (c) 2025 David Wegmann. All rights reserved. |
| 3 | +Released under Apache 2.0 license as described in the file LICENSE. |
| 4 | +Authors: David Wegmann |
| 5 | +-/ |
| 6 | + |
| 7 | +module |
| 8 | + |
| 9 | +public import Cslib.Languages.LambdaCalculus.LocallyNameless.Untyped.FullBeta |
| 10 | +public import Cslib.Languages.LambdaCalculus.LocallyNameless.Untyped.MultiApp |
| 11 | +public import Cslib.Languages.LambdaCalculus.LocallyNameless.Untyped.LcAt |
| 12 | + |
| 13 | +@[expose] public section |
| 14 | + |
| 15 | +set_option linter.unusedDecidableInType false |
| 16 | + |
| 17 | +namespace Cslib |
| 18 | + |
| 19 | +universe u |
| 20 | + |
| 21 | +namespace LambdaCalculus.LocallyNameless.Untyped.Term |
| 22 | + |
| 23 | +variable {Var : Type u} {t t' : Term Var} |
| 24 | + |
| 25 | +open FullBeta |
| 26 | + |
| 27 | +attribute [grind =] Finset.union_singleton |
| 28 | + |
| 29 | +/-- A term is strongly normalizing if every reduction sequence terminates at some point. |
| 30 | + This is ensured by the following type as inductive data must always be finite. -/ |
| 31 | +inductive SN {α} : Term α → Prop |
| 32 | +| sn t : (∀ t', t ⭢βᶠ t' → SN t') → SN t |
| 33 | + |
| 34 | +attribute [scoped grind .] SN.sn |
| 35 | + |
| 36 | +/-- A single β-reduction step preserves strong normalization. -/ |
| 37 | +lemma sn_step (t_st_t' : t ⭢βᶠ t') (sn_t : SN t) : SN t' := by |
| 38 | + grind [cases SN] |
| 39 | + |
| 40 | +/-- Multiple β-reduction steps also preserve strong normalization. -/ |
| 41 | +lemma sn_steps (t_st_t' : t ↠βᶠ t') (sn_t : SN t) : SN t' := by |
| 42 | + induction t_st_t' with grind [sn_step] |
| 43 | + |
| 44 | +/-- Free variables are strongly normalizing. -/ |
| 45 | +lemma sn_fvar {x : Var} : SN (fvar x) := by |
| 46 | + grind [cases FullBeta] |
| 47 | + |
| 48 | +/-- An application is strongly normalizing if the left and right terms are strongly normalizing, |
| 49 | + as well as all possible future top level abstraction application beta reductions -/ |
| 50 | +lemma sn_app (t s : Term Var) (sn_t : SN t) (sn_s : SN s) |
| 51 | + (hβ : ∀ {t' s' : Term Var}, t ↠βᶠ t'.abs → s ↠βᶠ s' → SN (t' ^ s')) : SN (t.app s) := by |
| 52 | + induction sn_t generalizing s with |
| 53 | + | sn t ht ih_t => |
| 54 | + induction sn_s with |
| 55 | + | sn s hs ih_s => |
| 56 | + constructor |
| 57 | + intro u hstep |
| 58 | + cases hstep with |
| 59 | + | beta _ _ => grind |
| 60 | + | appL _ h_s_red => apply ih_s _ h_s_red |
| 61 | + grind [Relation.ReflTransGen.head] |
| 62 | + | appR _ h_t_red => apply ih_t _ h_t_red _ (SN.sn s hs) |
| 63 | + grind [Relation.ReflTransGen.head] |
| 64 | + |
| 65 | +/-- The left side of a strongly normalizing application is strongly normalizing. -/ |
| 66 | +lemma sn_app_left (M N : Term Var) (lc_N : Term.LC N) (sn_MN : SN (M.app N)) : |
| 67 | + SN M := by |
| 68 | + generalize Heq : M.app N = P |
| 69 | + rw [Heq] at sn_MN |
| 70 | + induction sn_MN generalizing M N with grind |
| 71 | + |
| 72 | +/-- The right side of a strongly normalizing application is strongly normalizing. -/ |
| 73 | +lemma sn_app_right (M N : Term Var) (lc_N : Term.LC M) (sn_MN : SN (M.app N)) : |
| 74 | + SN N := by |
| 75 | + generalize Heq : M.app N = P |
| 76 | + rw [Heq] at sn_MN |
| 77 | + induction sn_MN generalizing M N with grind |
| 78 | + |
| 79 | +/-- A neutral term is a term of the form v t₁ … t_n where |
| 80 | + v is a variable and t₁ … t_n are strongly normalizing terms. -/ |
| 81 | +@[scoped grind] |
| 82 | +inductive Neutral : Term Var → Prop |
| 83 | +/-- Just a bound variable is neutral. -/ |
| 84 | +| bvar : ∀ n, Neutral (bvar n) |
| 85 | +/-- Just a free variable is neutral. -/ |
| 86 | +| fvar : ∀ x, Neutral (fvar x) |
| 87 | +/-- Applying a strongly normalizing term to a neutral term yields a neutral term. -/ |
| 88 | +| app : ∀ t1 t2, Neutral t1 → SN t2 → Neutral (app t1 t2) |
| 89 | + |
| 90 | +--attribute [scoped grind .] Neutral.bvar Neutral.fvar Neutral.app |
| 91 | + |
| 92 | +/-- Neutral terms only reduce to other neutral terms in a single step -/ |
| 93 | +lemma neutral_step (Hneut : Neutral t) (Hstep : t ⭢βᶠ t') : Neutral t' := by |
| 94 | + induction Hneut generalizing t' with grind [cases FullBeta, sn_step] |
| 95 | + |
| 96 | +/-- Neutral terms only reduce to other neutral terms in multiple steps -/ |
| 97 | +lemma neutral_steps (Hneut : Neutral t) (Hsteps : t ↠βᶠ t') : Neutral t' := by |
| 98 | + induction Hsteps <;> grind [neutral_step] |
| 99 | + |
| 100 | +/-- Neutral terms are strongly normalizing. -/ |
| 101 | +lemma sn_neutral (Hneut : Neutral t) : SN t := by |
| 102 | + induction Hneut with |
| 103 | + | app => grind [→ neutral_steps, sn_app] |
| 104 | + | _ => grind [cases FullBeta] |
| 105 | + |
| 106 | +/-- A lambda abstraction is strongly normalizing if its body is strongly normalizing. -/ |
| 107 | +lemma sn_abs [DecidableEq Var] [HasFresh Var] {M N : Term Var} (sn_MN : SN (M ^ N)) (lc_N : LC N) : |
| 108 | + SN (abs M) := by |
| 109 | + generalize h : (M ^ N) = M_open at sn_MN |
| 110 | + induction sn_MN generalizing M N with |
| 111 | + | sn => |
| 112 | + constructor |
| 113 | + intro _ h_step |
| 114 | + cases h_step with | abs _ H => grind [step_open_cong_l _ _ _ _ H] |
| 115 | + |
| 116 | +/-- A term of the form λ M N P_1 … P_n is strongly normalizing if |
| 117 | + 1. N is strongly normalizing, |
| 118 | + 1. M ^ N P₁ … Pₙ is strongly normalizing, |
| 119 | + 1. N is locally closed, |
| 120 | + 1. M ^ N P₁ … Pₙ is locally closed -/ |
| 121 | +lemma sn_abs_app_multiApp [DecidableEq Var] [HasFresh Var] {Ps} {M N : Term Var} |
| 122 | + (sn_N : SN N) (sn_MNPs : SN (multiApp (M ^ N) Ps)) |
| 123 | + (lc_N : LC N) (lc_MNPs : LC (multiApp (M ^ N) Ps)) : SN (multiApp (M.abs.app N) Ps) := by |
| 124 | + induction Ps with |
| 125 | + | nil => |
| 126 | + apply sn_app |
| 127 | + · grind [sn_abs] |
| 128 | + · exact sn_N |
| 129 | + · grind [→ steps_open_cong_abs, open_abs_lc, sn_steps] |
| 130 | + | cons P Ps ih => |
| 131 | + apply sn_app |
| 132 | + · cases lc_MNPs with grind [sn_app_left] |
| 133 | + · grind [sn_app_right] |
| 134 | + · intro Q' P' hstep1 hstep2 |
| 135 | + have ⟨M', N', Ps', h_M_red, h_N_red, h_Ps_red, h_cases⟩ := invert_abs_multiApp_mst hstep1 |
| 136 | + rcases h_cases with h_P | ⟨h_st1, h_st2⟩ |
| 137 | + · cases Ps' with grind |
| 138 | + · have innerSteps : (M ^ N).multiApp Ps ↠βᶠ (M' ^ N').multiApp Ps' := by |
| 139 | + trans |
| 140 | + · exact steps_multiApp_r h_Ps_red (by grind) |
| 141 | + · apply steps_multiApp_l |
| 142 | + · apply steps_open_cong_abs M M' N N' <;> grind [open_abs_lc] |
| 143 | + · grind [multiApp_steps_lc] |
| 144 | + apply sn_steps |
| 145 | + · calc ((M ^ N).multiApp Ps).app P |
| 146 | + _ ↠βᶠ ((M ^ N).multiApp Ps).app P' := by grind |
| 147 | + _ ↠βᶠ Q'.abs.app P' := redex_app_l_cong (.trans innerSteps h_st2) (by grind) |
| 148 | + _ ↠βᶠ Q' ^ P' := by grind [beta] |
| 149 | + · grind |
| 150 | + |
| 151 | +end LambdaCalculus.LocallyNameless.Untyped.Term |
| 152 | + |
| 153 | +end Cslib |
0 commit comments