Skip to content

Commit be301df

Browse files
committed
proof(lean4/LambdaCNO): close church_zero (1 of 6); document 5 spec-blocked sorries
L168 church_zero example - Was FALSE as stated. `(λf.λx.x)(λf.λx.x)` β-reduces by substituting the second copy for `f` in `LAbs (LVar 0)` — but `f` (de Bruijn 1 inside the inner LAbs) does not occur, so the result is `LAbs (LVar 0)` = `lambda_id`, NOT `church_zero`. Restated to the correct target and closed in a single β-step. The other 5 LambdaCNO sorries are spec-blocked, not proof-blocked. Replaced bare `sorry` with detailed deferral comments enumerating the spec choices the user needs to make: L114 lambda_id_is_cno (1 sorry inside) - β-reduction (λx.x) arg →* arg IS closed cleanly. - Remaining sorry is `isNormalForm arg` inside `evaluatesTo`. For arbitrary arg this is false; spec needs an arg-is-value hypothesis on `isLambdaCNO`, OR drop `isNormalForm nf` from `evaluatesTo`, OR restrict the universal to normal-form args. L138/L141 lambda_cno_composition (2 sorries inside) - `isLambdaCNO f` only gives `LApp f arg →* arg`; it does NOT tell us f = LAbs body, so we cannot perform the outer β-reduction. Spec needs either a syntactic f = LAbs _ constraint, an arg-as-value hypothesis, or an η-equivalence reformulation. L158 y_not_cno (1 sorry inside) - BetaReduceStar is inductive (only finite reduction sequences), so "no normal form exists for Y" cannot be proved directly. Need either an axiom y_combinator_no_normal_form (cheapest, matches file's existing axiom-heavy style - cf. eta_equivalence), a coinductive reformulation of reduction, or strong-normalization. L185 eta_expanded_id_is_cno (1 sorry, as written) - Same arg-is-value gap; the original explicit β-walk now actually builds under v4.16.0 (presumably because the seqComp abbrev change + ProgramState BEq derivation in CNO.lean indirectly affected simp normalization). Termination conjunct still gated on the spec choice. LambdaCNO file builds cleanly: 4 declarations with sorry, all documented.
1 parent bd31ddf commit be301df

1 file changed

Lines changed: 66 additions & 14 deletions

File tree

proofs/lean4/LambdaCNO.lean

Lines changed: 66 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,21 @@ def isLambdaCNO (t : LambdaTerm) : Prop :=
9696

9797
/-! ## Main Theorem: Identity is a CNO -/
9898

99+
/-- Identity is a (lambda) CNO.
100+
101+
Partially proved: the β-reduction `(λx.x) arg →* arg` IS closed
102+
cleanly. What remains as `sorry` is the `isNormalForm arg` conjunct
103+
embedded in `evaluatesTo`.
104+
105+
DEFERRED — spec gap, not a proof gap. `isLambdaCNO` (line 92)
106+
requires there *exists* a normal form `nf` of `LApp t arg`. For an
107+
arbitrary `arg` this is false (e.g. `(λx.x)((λy.y)z)` is reachable
108+
but not in normal form). The spec needs ONE of:
109+
(a) Add an `arg`-is-value (or `isNormalForm arg`) hypothesis
110+
inside the universal quantifier in `isLambdaCNO`; OR
111+
(b) Drop `isNormalForm nf` from `evaluatesTo`; OR
112+
(c) Restrict `isLambdaCNO` to quantify only over normal-form args.
113+
Each choice changes downstream theorems. Defer to user. -/
99114
theorem lambda_id_is_cno : isLambdaCNO lambda_id := by
100115
unfold isLambdaCNO lambda_id
101116
intro arg
@@ -104,16 +119,16 @@ theorem lambda_id_is_cno : isLambdaCNO lambda_id := by
104119
exists arg
105120
unfold evaluatesTo
106121
constructor
107-
· -- (λx.x) arg →* arg
122+
· -- (λx.x) arg →* arg — provable directly.
108123
apply BetaReduceStar.beta_step
109124
· apply BetaReduce.beta_app
110125
· unfold subst
111126
simp
112127
apply BetaReduceStar.beta_refl
113-
· -- arg is in normal form (assuming it's a value)
114-
sorry -- Requires assumption that arg is a value
128+
· -- DEFERRED — `isNormalForm arg` requires arg-is-value spec change.
129+
sorry
115130

116-
· -- Identity
131+
· -- Identity: same single β-step as above.
117132
apply BetaReduceStar.beta_step
118133
· apply BetaReduce.beta_app
119134
· unfold subst
@@ -126,6 +141,19 @@ theorem lambda_id_is_cno : isLambdaCNO lambda_id := by
126141
def lambda_compose (f g : LambdaTerm) : LambdaTerm :=
127142
LAbs (LApp f (LApp g (LVar 0)))
128143

144+
/-- Composing two lambda CNOs yields a CNO.
145+
146+
DEFERRED (×2) — spec gap. `isLambdaCNO f` only tells us that
147+
`(LApp f arg) →* arg` for any `arg` — that "applying `f` returns
148+
its argument back". It does NOT tell us `f = LAbs body`, so we
149+
cannot pattern-match on `f` to perform the outer β-reduction of
150+
`(λx. f (g x)) arg`. To close: ONE of
151+
(a) `isLambdaCNO` should require `t = LAbs _` (rule out
152+
non-abstraction "CNOs"); OR
153+
(b) Add a value/normal-form hypothesis on `f`/`g`; OR
154+
(c) Reformulate via the η-equivalence axiom on the outer LAbs.
155+
The first sorry also inherits the arg-is-value gap from
156+
`lambda_id_is_cno`. Defer to user. -/
129157
theorem lambda_cno_composition (f g : LambdaTerm) :
130158
isLambdaCNO f →
131159
isLambdaCNO g →
@@ -134,10 +162,9 @@ theorem lambda_cno_composition (f g : LambdaTerm) :
134162
unfold isLambdaCNO at *
135163
intro arg
136164
constructor
137-
· -- Terminates
165+
· -- DEFERRED — same arg-is-value gap as `lambda_id_is_cno`.
138166
sorry
139-
· -- Identity: ((λx. f (g x)) arg) →* arg
140-
-- Since f and g are both identity, this reduces to arg
167+
· -- DEFERRED — requires `f`/`g` to be syntactic abstractions.
141168
sorry
142169

143170
/-! ## Non-CNO Examples -/
@@ -148,24 +175,49 @@ def y_combinator : LambdaTerm :=
148175
(LAbs (LApp (LVar 1) (LApp (LVar 0) (LVar 0))))
149176
(LAbs (LApp (LVar 1) (LApp (LVar 0) (LVar 0)))))
150177

151-
/-- Y is NOT a CNO because it doesn't terminate -/
178+
/-- Y is NOT a CNO because it doesn't terminate.
179+
180+
DEFERRED — Lean's `BetaReduceStar` is *inductive* (only finite
181+
sequences), so "no normal form exists for Y" is a metatheoretic
182+
claim that cannot be discharged via the existing reduction
183+
relation. To close: ONE of
184+
(a) Add an axiom: `axiom y_combinator_no_normal_form :
185+
¬ ∃ nf, evaluatesTo (LApp y_combinator lambda_id) nf` and
186+
contradict `h_eval` with it (cheapest; matches the file's
187+
existing axiom-heavy style — cf. `eta_equivalence`);
188+
(b) Switch `BetaReduceStar` to coinductive and prove divergence
189+
via that; OR
190+
(c) Build a strong-normalization framework and show Y is not SN.
191+
Defer to user. -/
152192
theorem y_not_cno : ¬ isLambdaCNO y_combinator := by
153193
unfold isLambdaCNO y_combinator
154194
intro h
155-
-- Y applied to identity should terminate, but it doesn't
156195
have := h lambda_id
157-
obtain ⟨⟨nf, h_eval⟩, _⟩ := this
158-
sorry -- Y diverges
196+
obtain ⟨⟨_nf, _h_eval⟩, _⟩ := this
197+
sorry
159198

160199
/-! ## Church Encodings -/
161200

162201
/-- Church encoding of zero: λf.λx.x -/
163202
def church_zero : LambdaTerm :=
164203
LAbs (LAbs (LVar 0))
165204

166-
/-- Church encoding is a CNO for zero applied to zero -/
167-
example : BetaReduceStar (LApp church_zero church_zero) church_zero := by
168-
sorry
205+
/-- Church encoding β-reduces to the identity when applied to itself.
206+
207+
Spec correction: the original example claimed
208+
`(λf.λx.x)(λf.λx.x) →* λf.λx.x` (back to `church_zero`). That is
209+
*false*: β-reducing `(LAbs (LAbs (LVar 0))) (LAbs (LAbs (LVar 0)))`
210+
substitutes the second copy for `f` in `LAbs (LVar 0)`, but `f`
211+
(= de Bruijn 1 inside the inner LAbs) does not occur, so the
212+
result is `LAbs (LVar 0)` = `lambda_id`, *not* `church_zero`.
213+
Restating to the correct target makes the example provable in one
214+
β-step. -/
215+
example : BetaReduceStar (LApp church_zero church_zero) lambda_id := by
216+
apply BetaReduceStar.beta_step _ lambda_id
217+
· -- (LAbs (LAbs (LVar 0))) (LAbs (LAbs (LVar 0))) →β subst 0 _ (LAbs (LVar 0))
218+
-- = LAbs (LVar 0) = lambda_id
219+
exact BetaReduce.beta_app (LAbs (LVar 0)) church_zero
220+
· exact BetaReduceStar.beta_refl lambda_id
169221

170222
/-! ## Eta Equivalence -/
171223

0 commit comments

Comments
 (0)