Zulip Chat Archive
Stream: new members
Topic: Lean style - how to best pack API for a new definition
Rado Kirov (Sep 12 2025 at 06:01):
Say I am in the middle of a long proof and want to introduce a new local definition let x' = ...<something in terms of x,y,z...>. If I also decide to build a mini API of lemmas - have (h: <some prop about x' and x,y,z>): <some other prop about x',x,y,z>. I prove it using unfold, but then for the rest of the proof I try not to use unfold and just these lemmas. This works reasonably well, and I have done it in the past for long proofs.
What I am unclear, is if the proof gets even longer, and I want to extract something about x' and it's APIs to a stand-alone lemma, how to pass the original definition and APIs. Should I try to pack them in a structure? Or maybe capture the definition in a single _def lemma that fully captures the definition and pass that around?
Here is somewhat contrived example.
import Mathlib
lemma double_pos {X doubleX: Set ℚ} (h: ∀ x, x ∈ doubleX ↔ ∃ y, y ^ 2 = x) (y: ℚ): y ∈ doubleX → y ≥ 0 := by sorry
example (X: Set ℚ): True := by
-- some proof
let doubleX := {x ^ 2 | x ∈ X}
have doubleX_def (x: ℚ): x ∈ doubleX ↔ ∃ y, y ^ 2 = x := by
unfold doubleX
simp
have (x: ℚ): x ∈ doubleX → x ≥ 0 := by
unfold doubleX
simp
intro y hy hs
subst x
exact sq_nonneg y
-- rest of proof
tauto
Eric Wieser (Sep 12 2025 at 18:55):
If the proof starts to get really long, often you'd promote the let to a def
Eric Wieser (Sep 12 2025 at 18:56):
And then replace the have with lemmas about that def
Rado Kirov (Sep 12 2025 at 23:36):
I see so something like this
import Mathlib
def SquaredSet(X: Set ℚ) := {x ^ 2 | x ∈ X}
-- unfolds allowed here, this is the API
lemma SquaredSet_pos {X: Set ℚ}: ∀ x, x ∈ SquaredSet X -> x ≥ 0 := by
intro x h
unfold SquaredSet at h
simp at h
obtain ⟨y, hy, hs⟩ := h
subst x
exact sq_nonneg y
-- end of SquaredSet API
example (X: Set ℚ): True := by
-- some proof
let S := SquaredSet X
-- no unfolds here use API
have := SquaredSet_pos (X:=X)
-- rest of proof
tauto
Aaron Liu (Sep 12 2025 at 23:37):
similar yes
Eric Wieser (Sep 13 2025 at 00:06):
Note that SquaredSet is in mathlib as X ^ 2 with open scoped Pointwise
Eric Wieser (Sep 13 2025 at 00:07):
(also note that #naming tells you to capitalize it as squaredSet)
Damiano Testa (Sep 13 2025 at 04:00):
Is X ^ 2 under Pointwise the set of squares or the set of products on two elements from X?
Rado Kirov (Sep 13 2025 at 04:01):
Oh, the example doesn't matter at all, I just wrote some contrived let := ...
Rado Kirov (Sep 13 2025 at 04:04):
My point is in regular programming when I have a messy bunch of code, I know how to refactor it - find repeated expressions - extract to variables and function (with local or global scope). Modern IDEs even provide these basic refactoring for some languages.
However, in theorem proving land it is not so simple, once you pull out some expressions you have to manually keep unfolding it all proofs, which almost defeats the purpose. So one has to also declare some API lemmas with the factored out definition, but I don't have good sense how to package these API + definition, for a clean refactoring.
Kevin Buzzard (Sep 13 2025 at 08:32):
If you come across a definition which looks useful then factor it out and make some API and yes you're allowed to unfold. Alternatively if the API is always "unfold and then use API for what you got" then maybe an abbrev is in order.
Eric Wieser (Sep 13 2025 at 12:06):
Damiano Testa said:
Is
X ^ 2under Pointwise the set of squares or the set of products on two elements fromX?
We have instances for both!
Eric Wieser (Sep 13 2025 at 12:07):
(and so also, I don't know)
Aaron Liu (Sep 13 2025 at 12:42):
It depends on what you open
Eric Wieser (Sep 13 2025 at 15:38):
Does it?
Aaron Liu (Sep 13 2025 at 15:49):
I hope it does
Last updated: Dec 20 2025 at 21:32 UTC