Skip to content

Commit 23e7a99

Browse files
committed
refactor(CombinatoryLogic): extract helpers, simplify proofs
Add computes_of_total and RFindAbove_unfold helpers to eliminate repeated proof patterns. Simplify comp/pair_computes Part.mem chains and rfindAbove_induction via early subst + local helper. Remove dormant @[scoped grind] attributes from nil_correct and neg_correct.
1 parent 8f95cd3 commit 23e7a99

4 files changed

Lines changed: 57 additions & 74 deletions

File tree

Cslib/Languages/CombinatoryLogic/Basic.lean

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -288,7 +288,6 @@ theorem cond_correct (a x y : SKI) (u : Bool) (h : IsBool u a) :
288288

289289
/-- Neg := λ a. Cond FF TT a -/
290290
protected def Neg : SKI := SKI.Cond ⬝ FF ⬝ TT
291-
@[scoped grind →]
292291
theorem neg_correct (a : SKI) (ua : Bool) (h : IsBool ua a) : IsBool (¬ ua) (SKI.Neg ⬝ a) := by
293292
apply isBool_trans (a' := if ua then FF else TT)
294293
· apply cond_correct (h := h)

Cslib/Languages/CombinatoryLogic/List.lean

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,6 @@ theorem nil_def (c n : SKI) : (Nil ⬝ c ⬝ n) ↠ n :=
7474
NilPoly.toSKI_correct [c, n] (by simp)
7575

7676
/-- The empty list term correctly represents `[]`. -/
77-
@[scoped grind .]
7877
theorem nil_correct : IsChurchList [] Nil := nil_def
7978

8079
/-! ### Cons: Consing an element onto a list -/

Cslib/Languages/CombinatoryLogic/PartrecToSKI.lean

Lines changed: 48 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -115,51 +115,49 @@ def codeToSKINat : Code → SKI
115115

116116
/-! ### Correctness proofs -/
117117

118+
/-- Helper for total functions: if `c.eval` is total with output `g n`, and `t` reduces
119+
to a Church numeral for `g n`, then `t` computes `c.eval`. -/
120+
private theorem computes_of_total (t : SKI) (c : Code) (g : ℕ → ℕ)
121+
(heval : ∀ n, c.eval n = Part.some (g n))
122+
(hcorrect : ∀ n cn, IsChurch n cn → IsChurch (g n) (t ⬝ cn)) :
123+
Computes t c.eval := by
124+
intro n cn hcn m hm; rw [heval] at hm; obtain rfl := Part.some_injective hm
125+
exact hcorrect n cn hcn
126+
118127
/-- `Code.zero` computes the constant zero function. -/
119-
theorem zero_computes : Computes (K ⬝ SKI.Zero) (Code.eval .zero) := by
120-
intro n cn hcn m hm
121-
have h0 : Code.eval .zero n = Part.some 0 := by
122-
rw [show Code.zero = Code.const 0 from rfl, Code.eval_const]
123-
rw [h0] at hm; obtain rfl := Part.some_injective hm
124-
exact isChurch_trans 0 (MRed.K SKI.Zero cn) zero_correct
128+
theorem zero_computes : Computes (K ⬝ SKI.Zero) (Code.eval .zero) :=
129+
computes_of_total _ .zero (fun _ => 0)
130+
(fun n => by rw [show Code.zero = Code.const 0 from rfl, Code.eval_const])
131+
(fun _ _ _ => isChurch_trans 0 (MRed.K SKI.Zero _) zero_correct)
125132

126133
/-- `Code.succ` computes the successor function. -/
127-
theorem succ_computes : Computes SKI.Succ (Code.eval .succ) := by
128-
intro n cn hcn m hm
129-
have h0 : Code.eval .succ n = Part.some (n + 1) := by
130-
simp only [Code.eval, PFun.coe_val]
131-
rw [h0] at hm; obtain rfl := Part.some_injective hm
132-
exact succ_correct n cn hcn
134+
theorem succ_computes : Computes SKI.Succ (Code.eval .succ) :=
135+
computes_of_total _ .succ (· + 1)
136+
(fun _ => by simp only [Code.eval, PFun.coe_val])
137+
(fun n cn hcn => succ_correct n cn hcn)
133138

134139
/-- `Code.left` computes the left projection of `Nat.unpair`. -/
135-
theorem left_computes : Computes NatUnpairLeft (Code.eval .left) := by
136-
intro n cn hcn m hm
137-
have h0 : Code.eval .left n = Part.some (Nat.unpair n).1 := by
138-
simp only [Code.eval, PFun.coe_val]
139-
rw [h0] at hm; obtain rfl := Part.some_injective hm
140-
exact natUnpairLeft_correct n cn hcn
140+
theorem left_computes : Computes NatUnpairLeft (Code.eval .left) :=
141+
computes_of_total _ .left (fun n => (Nat.unpair n).1)
142+
(fun _ => by simp only [Code.eval, PFun.coe_val])
143+
(fun n cn hcn => natUnpairLeft_correct n cn hcn)
141144

142145
/-- `Code.right` computes the right projection of `Nat.unpair`. -/
143-
theorem right_computes : Computes NatUnpairRight (Code.eval .right) := by
144-
intro n cn hcn m hm
145-
have h0 : Code.eval .right n = Part.some (Nat.unpair n).2 := by
146-
simp only [Code.eval, PFun.coe_val]
147-
rw [h0] at hm; obtain rfl := Part.some_injective hm
148-
exact natUnpairRight_correct n cn hcn
146+
theorem right_computes : Computes NatUnpairRight (Code.eval .right) :=
147+
computes_of_total _ .right (fun n => (Nat.unpair n).2)
148+
(fun _ => by simp only [Code.eval, PFun.coe_val])
149+
(fun n cn hcn => natUnpairRight_correct n cn hcn)
149150

150151
/-- Composition of computable functions is computable. -/
151152
theorem comp_computes {f g : ℕ →. ℕ} {tf tg : SKI}
152153
(hf : Computes tf f) (hg : Computes tg g) :
153154
Computes (B ⬝ tf ⬝ tg) (fun n => g n >>= f) := by
154155
intro n cn hcn m hm
155156
simp only at hm
156-
have hm' : m ∈ (g n >>= f) := by rw [hm]; exact Part.mem_some m
157-
obtain ⟨intermediate, hint_mem, hm_mem⟩ := Part.mem_bind_iff.mp hm'
158-
have hgn : g n = Part.some intermediate := Part.eq_some_iff.mpr hint_mem
159-
have hfint : f intermediate = Part.some m := Part.eq_some_iff.mpr hm_mem
160-
have hcint := hg n cn hcn intermediate hgn
161-
have hcm := hf intermediate (tg ⬝ cn) hcint m hfint
162-
exact isChurch_trans _ (B_def tf tg cn) hcm
157+
obtain ⟨intermediate, hint_mem, hm_mem⟩ := Part.mem_bind_iff.mp (hm ▸ Part.mem_some m)
158+
have hcint := hg n cn hcn intermediate (Part.eq_some_iff.mpr hint_mem)
159+
exact isChurch_trans _ (B_def tf tg cn)
160+
(hf intermediate (tg ⬝ cn) hcint m (Part.eq_some_iff.mpr hm_mem))
163161

164162
/-- Pairing of computable functions is computable. -/
165163
theorem pair_computes {f g : ℕ →. ℕ} {tf tg : SKI}
@@ -168,24 +166,13 @@ theorem pair_computes {f g : ℕ →. ℕ} {tf tg : SKI}
168166
(fun n => Nat.pair <$> f n <*> g n) := by
169167
intro n cn hcn m hm
170168
simp only at hm
171-
-- hm : Nat.pair <$> f n <*> g n = Part.some m
172-
have hm' : m ∈ (Nat.pair <$> f n <*> g n) := by rw [hm]; exact Part.mem_some m
173-
-- Unfold <*> into bind: pf <*> pa = pf >>= fun h => h <$> pa
174-
have hm_bind : m ∈ Part.bind (Part.map Nat.pair (f n)) (fun h => Part.map h (g n)) := hm'
175-
obtain ⟨h, hh_mem, hm_in_h⟩ := Part.mem_bind_iff.mp hm_bind
176-
obtain ⟨a, ha_mem, hh_eq⟩ := (Part.mem_map_iff _).mp hh_mem
177-
subst hh_eq
178-
obtain ⟨b, hb_mem, hm_eq⟩ := (Part.mem_map_iff _).mp hm_in_h
179-
have hfn : f n = Part.some a := Part.eq_some_iff.mpr ha_mem
180-
have hgn : g n = Part.some b := Part.eq_some_iff.mpr hb_mem
181-
have hca := hf n cn hcn a hfn
182-
have hcb := hg n cn hcn b hgn
183-
subst hm_eq
184-
have hred : (S ⬝ (B ⬝ NatPair ⬝ tf) ⬝ tg ⬝ cn) ↠
185-
(NatPair ⬝ (tf ⬝ cn) ⬝ (tg ⬝ cn)) := calc
186-
_ ↠ (B ⬝ NatPair ⬝ tf) ⬝ cn ⬝ (tg ⬝ cn) := MRed.S _ _ _
187-
_ ↠ NatPair ⬝ (tf ⬝ cn) ⬝ (tg ⬝ cn) := MRed.head _ (B_def _ _ _)
188-
exact isChurch_trans _ hred (natPair_correct a b _ _ hca hcb)
169+
obtain ⟨h, hh_mem, hm_in_h⟩ := Part.mem_bind_iff.mp (hm ▸ Part.mem_some m)
170+
obtain ⟨a, ha_mem, rfl⟩ := (Part.mem_map_iff _).mp hh_mem
171+
obtain ⟨b, hb_mem, rfl⟩ := (Part.mem_map_iff _).mp hm_in_h
172+
have hca := hf n cn hcn a (Part.eq_some_iff.mpr ha_mem)
173+
have hcb := hg n cn hcn b (Part.eq_some_iff.mpr hb_mem)
174+
exact isChurch_trans _ ((MRed.S _ _ _).trans (MRed.head _ (B_def _ _ _)))
175+
(natPair_correct a b _ _ hca hcb)
189176

190177
/-- Helper: `Rec` correctly implements primitive recursion from `Code.prec`. -/
191178
private theorem prec_rec_correct (f g : Code) (tf tg : SKI)
@@ -257,36 +244,30 @@ private theorem rfindAbove_induction (f : Code) (tf : SKI)
257244
(∀ i < n, ∃ vi, vi ≠ 0
258245
f.eval (Nat.pair a₀ (m + i)) = Part.some vi) →
259246
IsChurch (m + n) (RFindAbove ⬝ x ⬝ g) := by
247+
subst hg
248+
-- Helper: `B ⬝ tf ⬝ (NatPair ⬝ ca) ⬝ x` computes `f.eval (Nat.pair a₀ m)`.
249+
have hgx : ∀ m x, IsChurch m x → ∀ v, f.eval (Nat.pair a₀ m) = Part.some v →
250+
IsChurch v (B ⬝ tf ⬝ (NatPair ⬝ ca) ⬝ x) := fun m x hx v hv =>
251+
isChurch_trans _ (B_def tf (NatPair ⬝ ca) x)
252+
(ihf _ _ (natPair_correct a₀ m ca x hca hx) v hv)
260253
intro n
261254
induction n with
262255
| zero =>
263256
intro m x hx hroot _
264257
simp only [Nat.add_zero] at hroot ⊢
265-
apply isChurch_trans (a' := RFindAboveAux ⬝ RFindAbove ⬝ x ⬝ g)
266-
· apply MRed.head; apply MRed.head; exact fixedPoint_correct _
258+
apply isChurch_trans _ (RFindAbove_unfold x _)
267259
apply isChurch_trans (a' := x)
268-
· apply rfindAboveAux_base
269-
-- Need: IsChurch 0 (g ⬝ x)
270-
subst hg
271-
apply isChurch_trans _ (B_def tf (NatPair ⬝ ca) x)
272-
have hpair := natPair_correct a₀ m ca x hca hx
273-
exact ihf _ _ hpair 0 hroot
260+
· exact rfindAboveAux_base _ _ _ (hgx m x hx 0 hroot)
274261
· exact hx
275262
| succ n ih =>
276263
intro m x hx hroot hbelow
277-
apply isChurch_trans (a' := RFindAboveAux ⬝ RFindAbove ⬝ x ⬝ g)
278-
· apply MRed.head; apply MRed.head; exact fixedPoint_correct _
279-
-- f at m is nonzero, so step
264+
apply isChurch_trans _ (RFindAbove_unfold x _)
280265
obtain ⟨v₀, hv₀_ne, hv₀_eval⟩ := hbelow 0 (by omega)
281266
simp only [Nat.add_zero] at hv₀_eval
282-
apply isChurch_trans (a' := RFindAbove ⬝ (SKI.Succ ⬝ x) ⬝ g)
267+
apply isChurch_trans (a' := RFindAbove ⬝ (SKI.Succ ⬝ x) ⬝ _)
283268
· apply rfindAboveAux_step (m := v₀ - 1)
284-
subst hg
285-
apply isChurch_trans _ (B_def tf (NatPair ⬝ ca) x)
286-
have hpair := natPair_correct a₀ m ca x hca hx
287-
have hv₀_pos : v₀ - 1 + 1 = v₀ := Nat.succ_pred_eq_of_ne_zero hv₀_ne
288-
rw [hv₀_pos]
289-
exact ihf _ _ hpair v₀ hv₀_eval
269+
have : v₀ - 1 + 1 = v₀ := Nat.succ_pred_eq_of_ne_zero hv₀_ne
270+
rw [this]; exact hgx m x hx v₀ hv₀_eval
290271
· have h := ih (m + 1) (SKI.Succ ⬝ x) (succ_correct m x hx)
291272
(by rw [show m + 1 + n = m + (n + 1) from by omega]; exact hroot)
292273
(by

Cslib/Languages/CombinatoryLogic/Recursion.lean

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -298,16 +298,22 @@ theorem rfindAboveAux_step (R₀ f a : SKI) {m : Nat} (hfa : IsChurch (m + 1) (f
298298

299299
/-- Find the minimal root of `fNat` above a number n -/
300300
def RFindAbove : SKI := RFindAboveAux.fixedPoint
301+
302+
/-- One unfolding of `RFindAbove`: apply the fixed-point combinator once. -/
303+
theorem RFindAbove_unfold (x g : SKI) :
304+
(RFindAbove ⬝ x ⬝ g) ↠ RFindAboveAux ⬝ RFindAbove ⬝ x ⬝ g := by
305+
apply MRed.head; apply MRed.head; exact fixedPoint_correct _
306+
301307
theorem RFindAbove_correct (fNat : Nat → Nat) (f x : SKI)
302308
(hf : ∀ i : Nat, ∀ y : SKI, IsChurch i y → IsChurch (fNat i) (f ⬝ y))
303309
(n m : Nat) (hx : IsChurch m x) (hroot : fNat (m+n) = 0) (hpos : ∀ i < n, fNat (m+i) ≠ 0) :
304310
IsChurch (m+n) (RFindAbove ⬝ x ⬝ f) := by
305311
induction n generalizing m x
306-
all_goals apply isChurch_trans (a' := RFindAboveAux ⬝ RFindAbove ⬝ x ⬝ f)
307-
case zero.a =>
312+
all_goals apply isChurch_trans _ (RFindAbove_unfold x f)
313+
case zero =>
308314
apply isChurch_trans (a' := x) <;>
309315
grind [rfindAboveAux_base]
310-
case succ.a n ih =>
316+
case succ n ih =>
311317
apply isChurch_trans (a' := RFindAbove ⬝ (SKI.Succ ⬝ x) ⬝ f)
312318
· let y := (fNat m).pred
313319
have : IsChurch (y + 1) (f ⬝ x) := by
@@ -317,8 +323,6 @@ theorem RFindAbove_correct (fNat : Nat → Nat) (f x : SKI)
317323
assumption
318324
· replace ih := ih (SKI.Succ ⬝ x) (m + 1) (succ_correct _ x hx)
319325
grind
320-
-- close the `h` goals of the above `apply isChurch_trans`
321-
all_goals {apply MRed.head; apply MRed.head; exact fixedPoint_correct _}
322326

323327

324328
/-- Ordinary root finding is root finding above zero -/

0 commit comments

Comments
 (0)