feat: de Bruijn Syntax for Untyped Lambda Calculus and a proof of Church-Rosser with Parallel Reduction#475
feat: de Bruijn Syntax for Untyped Lambda Calculus and a proof of Church-Rosser with Parallel Reduction#475zayn7lie wants to merge 13 commits intoleanprover:mainfrom
Conversation
chenson2018
left a comment
There was a problem hiding this comment.
Hi, thanks for your interest in contributing to CSLib! We do have Church-Rosser for locally nameless binding, but I think we are interested in having the more common de Bruijn indices representation as well.
I see there is a disclosure of AI usage, but this looks like its been mostly cleaned up pretty well, so thank you.
Below are some initial reviews about making this fit into CSLib conventions.
| | app t₁ t₂ ih₁ ih₂ => simp_all | ||
|
|
||
| /-- Communitivity of incre. -/ | ||
| public theorem incre_comm {i j k l t} : |
There was a problem hiding this comment.
I think we can clean up some of the arithmetic in theorems like this, but I'll wait until we have more high-level changes done first to give specific suggestions.
| | appL {t t' u} : Beta t t' → Beta (t·u) (t'·u) | ||
| | appR {t u u'} : Beta u u' → Beta (t·u) (t·u') | ||
| | red (t' s : Term) : Beta ((λ.t')·s) (t'.sub 0 s) | ||
| public abbrev BetaStar := Relation.ReflTransGen Beta |
There was a problem hiding this comment.
We use the attribute reduction_sys for generating notations for reductions and the multi-step closure.
There was a problem hiding this comment.
There was a problem hiding this comment.
There was a problem hiding this comment.
At the same time, would you know how to type ⭢ in Lean for single reduction?
Thanks for notification, sorry for confusion. |
I don't understand this comment. It looks as I would expect for this binding scheme. |
Please read the header comment docs of |
|
Can you rename |
I am somehow hesitant to do that. The current |
|
I agree that we should almost always use the notation and corresponding naming, which is then based off I've started a second pass of reviews which I'll try to have complete in a few days. |
…lation`, and add `rtc_eq_of_sandwich`
…lation`, and add `rtc_eq_of_sandwich`
…multi-step closure
| (h₁ : ∀ {a b}, r a b → p a b) | ||
| (h₂ : ∀ {a b}, p a b → ReflTransGen r a b) : | ||
| ∀ {a b}, ReflTransGen r a b ↔ ReflTransGen p a b := by |
There was a problem hiding this comment.
Perhaps better as
| (h₁ : ∀ {a b}, r a b → p a b) | |
| (h₂ : ∀ {a b}, p a b → ReflTransGen r a b) : | |
| ∀ {a b}, ReflTransGen r a b ↔ ReflTransGen p a b := by | |
| (h₁ : r ≤ p) | |
| (h₂ : p ≤ ReflTransGen r) : | |
| ReflTransGen r = ReflTransGen p := by |
I think this was discussed on Zulip?
There was a problem hiding this comment.
Yes, this thread. I'd use the naming and shorter proof discussed there as well.
| | Par.var t => cases em (t = n) with | ||
| | inl h => | ||
| simp_all only [sub, subst, ↓reduceIte, | ||
| decre_incre_elim, incre_par] | ||
| | inr h => cases em (t < n) with |
There was a problem hiding this comment.
I think this is better handled with obtain h | h | h := lt_trichotomy t n
| notation:max "𝕧" str => Term.var str | ||
| notation:max "λ." t => Term.abs t | ||
| infixl:77 "·" => Term.app |
There was a problem hiding this comment.
These should use @[inherit_doc]
There was a problem hiding this comment.
The application notation is also problematic, as it conflicts the core \. notation.
| /-- `subst j s t` substitutes `j` with term `s` in `t`. -/ | ||
| @[expose] public def subst (j : Nat) (s : Term) : Term → Term | ||
| | var k => if k = j then s else var k | ||
| | abs t => abs (subst (j + 1) (incre 1 0 s) t) | ||
| | app t u => app (subst j s t) (subst j s u) | ||
|
|
||
| /-- `decre i l t` decrements `i` for all free vars `≥ l + i`. | ||
| the reason using `l + i` is that it is more explicit for | ||
| free variable elimination. For example, after eliminating | ||
| `var k` for Term `t` from the most outside, `decre 1 k t` | ||
| will close the gap caused by `k` elimination. -/ | ||
| @[expose] public def decre (i : Nat) (l : Nat) : Term → Term | ||
| | var k => if l + i ≤ k then var (k - i) else var k | ||
| | abs t => abs (decre i (l + 1) t) | ||
| | app t u => app (decre i l t) (decre i l u) |
There was a problem hiding this comment.
Should this be a single operation?
There was a problem hiding this comment.
Hmm, I don't think I've ever seen it done that way before? It might be awkward not having incre and decre as inverses. I'm not sure though.
| | app t u => app (decre i l t) (decre i l u) | ||
|
|
||
| /-- Substitute into the body of a lambda: `(λ.t) s` -/ | ||
| @[expose] public def sub (t : Term) (n : Nat) (s : Term) := |
There was a problem hiding this comment.
| @[expose] public def sub (t : Term) (n : Nat) (s : Term) := | |
| @[expose] public def sub (t : Term) (n : Nat) (s : Term) : Term := |
| | var : Nat → Term | ||
| | abs : Term → Term | ||
| | app : Term → Term → Term |
There was a problem hiding this comment.
Please write a docstring for each of these
chenson2018
left a comment
There was a problem hiding this comment.
This is still not comprehensive, but a few more comments. The comment about squeezing terminal simp applies throughout and is one factor making proofs much longer than they need to be. Could you work on fixing this a bit?
There was a problem hiding this comment.
Let's follow the convention of naming this file Basic.lean.
| -/ | ||
|
|
||
|
|
||
| namespace Lambda |
There was a problem hiding this comment.
The namespacing should closely follow the previous lamba calculi developments. I think that would make this Cslib.LambdaCalculus.Unscoped.Untyped.
| open Term | ||
| namespace Term |
There was a problem hiding this comment.
It is redundant to both open and then enter a namespace
| open Term | |
| namespace Term | |
| namespace Term |
| infixl:77 "·" => Term.app | ||
|
|
||
| /-- `incre i l t` increments `i` for all free vars `≥ l`. -/ | ||
| @[expose] public def incre (i : Nat) (l : Nat) : Term → Term |
There was a problem hiding this comment.
As I mentioned previously, I would remove everywhere you use public and @[expose] in favor of @[expose] public section
| induction t generalizing l with | ||
| | var k => simp_all only [incre, Nat.add_zero, ite_self] | ||
| | abs t ih => simp_all only [incre] | ||
| | app t u iht ihu => simp_all only [incre] |
There was a problem hiding this comment.
These simp are terminal, so do not need to be squeezed. Personally I would just write
| induction t generalizing l with | |
| | var k => simp_all only [incre, Nat.add_zero, ite_self] | |
| | abs t ih => simp_all only [incre] | |
| | app t u iht ihu => simp_all only [incre] | |
| induction t generalizing l with grind [incre] |
| notation:max "𝕧" str => Term.var str | ||
| notation:max "λ." t => Term.abs t | ||
| infixl:77 "·" => Term.app |
There was a problem hiding this comment.
The application notation is also problematic, as it conflicts the core \. notation.
| (h₁ : ∀ {a b}, r a b → p a b) | ||
| (h₂ : ∀ {a b}, p a b → ReflTransGen r a b) : | ||
| ∀ {a b}, ReflTransGen r a b ↔ ReflTransGen p a b := by |
There was a problem hiding this comment.
Yes, this thread. I'd use the naming and shorter proof discussed there as well.
Main contributions
Par) and its basic properties.Diamond,Confluent) for binary relations.The development follows the classical proof strategy:
parallel reduction -> diamond -> confluence -> Church–Rosser.Design choices
(
Diamond,Confluent) to keep the proof modular.Use of AI