Skip to content

feat(untyped): standardization theorem for the lambda calculus#679

Open
m-ow wants to merge 3 commits into
leanprover:mainfrom
m-ow:standardization-theorem
Open

feat(untyped): standardization theorem for the lambda calculus#679
m-ow wants to merge 3 commits into
leanprover:mainfrom
m-ow:standardization-theorem

Conversation

@m-ow

@m-ow m-ow commented Jun 24, 2026

Copy link
Copy Markdown
Contributor

This PR proves the standardization theorem: if M beta-reduces to N in any number of steps, then N is reachable from M by a standard reduction.

Builds on #671.

@lengyijun

lengyijun commented Jul 5, 2026

Copy link
Copy Markdown
Contributor

Looking for your next pr !
I will start to prove "two variables are not enough" soon
This pr is very important for me

@chenson2018 chenson2018 self-assigned this Jul 5, 2026
@lengyijun

Copy link
Copy Markdown
Contributor

Could you share your next PR related to "leftmost reduction"?
I would like to base the development of the Fokker Challenge on your code.

@m-ow

m-ow commented Jul 7, 2026

Copy link
Copy Markdown
Contributor Author

Hi! @lengyijun My branch is still a bit too messy to share right now, but I expect to open the PR very soon.
Sorry for the wait, and thanks for bearing with me!

@m-ow m-ow force-pushed the standardization-theorem branch from 7f7a6cd to 93dfbbb Compare July 7, 2026 18:42
@m-ow

m-ow commented Jul 8, 2026

Copy link
Copy Markdown
Contributor Author

opened #700 :)

@chenson2018 chenson2018 left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems straightforward, just some style nitpicks.


/-- A single Call-by-Name step is a full β-reduction. -/
lemma CBN.step_to_redex (step : M ⭢ₙ N) : M ↠βᶠ N := by
induction step <;> grind [FullBeta.redex_app_l_cong, Relation.ReflTransGen.single]

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Something I recently have been more strict about is trying not to not is golf proofs of the form

induction foo
· grind [bar]
· grind [baz]

into a single induction foo <;> grind [bar, baz] for readability and performance reasons.

So I'd write at least

Suggested change
induction step <;> grind [FullBeta.redex_app_l_cong, Relation.ReflTransGen.single]
induction step with
· grind [Relation.ReflTransGen.single]
· grind [FullBeta.redex_app_l_cong]

(or even be tempted to not use grind at all for such a short proof)

This same idea applies to other proofs in this file.

cases h_beta
exact rdx (by assumption) (by assumption) .refl (lc_refl _ lc_N)
case app L _ _ lc_L _ ih =>
exact app (ih (by cases lc_N; assumption)) (lc_refl L lc_L)

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd at least do

Suggested change
exact app (ih (by cases lc_N; assumption)) (lc_refl L lc_L)
cases lc_N
exact app (ih (by assumption)) (lc_refl L lc_L)

for readability. It'd also be easy to make the assumption usages explicit if you'd like.

Comment on lines +81 to +82
| rdx _ lc_Z cbn_m std_body =>
exact rdx (CBN.lc_l step_M) lc_Z (.head step_M cbn_m) std_body

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fits on one line?

Suggested change
| rdx _ lc_Z cbn_m std_body =>
exact rdx (CBN.lc_l step_M) lc_Z (.head step_M cbn_m) std_body
| rdx _ lc_Z cbn_m std_body => exact rdx (CBN.lc_l step_M) lc_Z (.head step_M cbn_m) std_body

Comment on lines +112 to +114
have h_neq : x ≠ y := by aesop
rw [← Term.subst_open_var y x N m h_neq lc_N, ← Term.subst_open_var y x N' m' h_neq lc_N']
exact ih y (by aesop) hN lc_N lc_N'

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We prefer grind to aesop

Suggested change
have h_neq : x ≠ y := by aesop
rw [← Term.subst_open_var y x N m h_neq lc_N, ← Term.subst_open_var y x N' m' h_neq lc_N']
exact ih y (by aesop) hN lc_N lc_N'
have h_neq : x ≠ y := by grind
rw [← Term.subst_open_var y x N m h_neq lc_N, ← Term.subst_open_var y x N' m' h_neq lc_N']
exact ih y (by grind) hN lc_N lc_N'

Comment on lines +119 to +120
exact rdx (Term.subst_lc (x := x) lc_m lc_N) (Term.subst_lc (x := x) lc_n lc_N)
(CBN.steps_subst x cbn_m lc_N) std_p_subst

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No need for the implicits here, can fit on one line:

Suggested change
exact rdx (Term.subst_lc (x := x) lc_m lc_N) (Term.subst_lc (x := x) lc_n lc_N)
(CBN.steps_subst x cbn_m lc_N) std_p_subst
exact rdx (subst_lc lc_m lc_N) (subst_lc lc_n lc_N) (CBN.steps_subst x cbn_m lc_N) std_p_subst

case abs ih =>
apply Standard.abs <| free_union [fv] Var
intro x hx
exact ih x (by aesop) (Term.beta_lc lc_M (by constructor))

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
exact ih x (by aesop) (Term.beta_lc lc_M (by constructor))
exact ih x (by grind) (Term.beta_lc lc_M (by constructor))

Comment on lines +150 to +151
have step2 : Term.app (Term.abs m') n ↠βᶠ (m' ^ n) :=
.single (Xi.base (Beta.beta (CBN.steps_lc_r lc_m cbn_m) lc_n))

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In general, I think it'd be nicer to use the Term namespace to your advantage for formatting

Suggested change
have step2 : Term.app (Term.abs m') n ↠βᶠ (m' ^ n) :=
.single (Xi.base (Beta.beta (CBN.steps_lc_r lc_m cbn_m) lc_n))
have step2 : m'.abs.app n ↠βᶠ m' ^ n := .single (.base (.beta (CBN.steps_lc_r lc_m cbn_m) lc_n))

Comment on lines +178 to +179
have h_subst := Standard.subst (h_body y (by aesop)) hN y lc_N lc_N'
rw [← Term.subst_intro y N M (by aesop), ← Term.subst_intro y N' M' (by aesop)] at h_subst

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
have h_subst := Standard.subst (h_body y (by aesop)) hN y lc_N lc_N'
rw [← Term.subst_intro y N M (by aesop), ← Term.subst_intro y N' M' (by aesop)] at h_subst
have h_subst := Standard.subst (h_body y (by grind)) hN y lc_N lc_N'
rw [← Term.subst_intro y N M (by grind), ← Term.subst_intro y N' M' (by grind)] at h_subst

case abs ih_beta =>
apply Standard.abs <| free_union [fv] Var
intro y hy
exact ih y (by aesop) (ih_beta y (by aesop))

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
exact ih y (by aesop) (ih_beta y (by aesop))
exact ih y (by grind) (ih_beta y (by grind))

exact h_subst

/-- A standard reduction followed by a full β-step is a standard reduction. -/
lemma Standard.trans_step (h1 : M ⭢ₛ P) (h2 : P ⭢βᶠ N) : M ⭢ₛ N := by

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe it would be useful to have instances for these like Trans (· ⭢ₛ · : Term Var → Term Var → Prop) (· ⭢βᶠ ·) (· ⭢ₛ ·) in this case? Just a thought for later.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants