Loading...
Loading...
Compare original and translation side by side
sorrymaxHeartbeatsmaxHeartbeatsge_or_gtdiscrete_fieldge_or_gtdiscrete_fieldOption(0 : ℝ)⁻¹ = 0FunLikeSetLikeIsHomext@[simp]unfoldshow ... from rflOption(0 : ℝ)⁻¹ = 0FunLikeSetLikeIsHomext@[simp]unfoldshow ... from rfl:= sorrysorryhavesufficescalcsorryexample (a b c d : ℝ) (h : c = d * a + b) (h' : b = a * d) : c = 2 * a * d := by
calc
c = d * a + b := sorry
_ = d * a + a * d := sorry
_ = 2 * a * d := sorry:= sorrysorrysorryhavesufficescalcexample (a b c d : ℝ) (h : c = d * a + b) (h' : b = a * d) : c = 2 * a * d := by
calc
c = d * a + b := sorry
_ = d * a + a * d := sorry
_ = 2 * a * d := sorry·multiGoalshowshowchangecalchavesufficestrace_statedonelake env lean Path/To/File.lean·multiGoalshowshowchangecalchavesufficestrace_statedonelake env lean Path/To/File.leanlake buildsorry#print axioms myTheoremLean.collectAxioms[propext, Classical.choice, Quot.sound]sorrynative_decidelinter.mathlibStandardSetlinter.auxLemmalinter.style.maxHeartbeatslinter.style.multiGoallinter.style.setOptionlinter.style.showlinter.flexiblelinter.style.missingEndlinter.style.openClassicalunused*InTypenativeDecide#lintsimpNFweak.@[env_linter]lake buildsorrysorry#print axioms myTheoremLean.collectAxioms[propext, Classical.choice, Quot.sound]sorrynative_decidelinter.mathlibStandardSetlinter.auxLemmalinter.style.maxHeartbeatslinter.style.multiGoallinter.style.setOptionlinter.style.showlinter.flexiblelinter.style.missingEndlinter.style.openClassicalunused*InTypenativeDecide#lintsimpNFweak.@[env_linter]exampleexact?apply?havetheorem min_comm (a b : ℝ) : min a b = min b a := by
have h : ∀ x y : ℝ, min x y ≤ min y x := by
intro x y
apply le_min
· show min x y ≤ y
exact min_le_right x y
· show min x y ≤ x
exact min_le_left x y
apply le_antisymm
· show min a b ≤ min b a
exact h a b
· show min b a ≤ min a b
exact h b aexampleexact?apply?havetheorem min_comm (a b : ℝ) : min a b = min b a := by
have h : ∀ x y : ℝ, min x y ≤ min y x := by
intro x y
apply le_min
· show min x y ≤ y
exact min_le_right x y
· show min x y ≤ x
exact min_le_left x y
apply le_antisymm
· show min a b ≤ min b a
exact h a b
· show min b a ≤ min a b
exact h b a| Rule | Why | Enforced by |
|---|---|---|
Never unfold definitions downstream; | API lemmas are the abstraction boundary | review ("missing API" smell) |
Terminal | squeezed terminal calls bury the key lemmas and break on renames | style guide |
One focused goal at a time ( | kills goal-ordering fragility | |
| stated goals stay honest | |
No | debugging scaffolding | |
State lemmas in simp-normal form, | simp matches syntactically | |
| Golf only when the result is at least as readable; trivial results exempt | short ≠ better | review |
| global instances degrade all typeclass search | review |
| Name lemmas from their statements (see naming reference) | names become guessable without search | |
| Search a bare goal by shape before writing a helper or claiming an API gap | names are not always guessable from the target | |
| Generally one tactic invocation per line; a one-line closing proof is the exception | preserves readable proof structure without inventing an absolute rule | style guide |
Gate | grep matches comments, misses unproved helpers | axiom audit in CI |
| Prefer simp-lemma LHSs keyed on structure, not numerals; one spelling per constant | | |
Re-derive every | lists do not transfer between look-alike goals | |
Every | copy-pasted budgets carry no information | |
Conditional simp lemma fires shallow but not deep → raise | chained side conditions truncate silently, no diagnostic | diagnosis (proof-style, simp discipline) |
| Every project-specific convention gets a custom linter, in CI from day one | review misses the 29-of-30 failure mode | |
| 规则 | 原因 | 强制执行方式 |
|---|---|---|
下游绝不展开定义; | API引理是抽象边界 | 审阅(“缺少API”的不良气味) |
末尾 | 压缩的末尾调用会隐藏关键引理,且在重命名时失效 | 风格指南 |
一次只聚焦一个目标( | 消除目标顺序的脆弱性 | |
| 保持陈述的目标真实准确 | |
最终代码中不得包含 | 移除调试脚手架 | |
引理陈述使用simp标准形式,用 | simp进行语法匹配 | |
| 仅当结果至少同样可读时才简化代码; trivial结果除外 | 短≠更好 | 审阅 |
| 全局实例会降低所有类型类搜索的性能 | 审阅 |
| 根据陈述命名引理(请参考命名参考) | 无需搜索即可推测名称 | |
| 在编写辅助定理或声称API缺口前,先按形状搜索空目标 | 名称并非总能从目标中推测 | |
| 通常每行一个策略调用;单行收尾证明是例外 | 在不制定绝对规则的前提下,保留可读的证明结构 | 风格指南 |
使用 | grep会匹配注释,遗漏未证明的辅助定理 | CI中的公理审计 |
| 优先选择基于结构而非数字的simp引理左部;每个常量仅一种写法 | | |
每个 | 列表无法在相似目标间迁移 | |
每个 | 复制粘贴的预算没有任何信息 | |
条件simp引理浅层触发但深层不触发 → 提高 | 链式附带条件会静默截断,无诊断信息 | 诊断(证明风格、simp规则) |
| 每个项目专属规范都要有自定义检查器,从项目第一天就加入CI | 审阅会遗漏“30个中有29个失败”的情况 | |
| Excuse | Reality |
|---|---|
| "The proof compiles, ship it" | Compiling is the floor. A monolithic tactic block that only Lean can read will break silently at the next Mathlib bump and no one will be able to repair it. |
| "Unfolding the definition is simpler than writing API lemmas" | Every downstream |
| "Squeezing every simp makes the proof faster and more robust" | Backwards for terminal simp calls: the squeezed list breaks on every rename and drowns the signal. Squeeze non-terminal calls only. |
| "It's shorter, therefore better" | Mathlib review policy: golfing is fine only when it does not sacrifice readability. Length is not the target; legibility is. |
| "I'll restructure it into lemmas after it works" | After it works, the structure is load-bearing and tangled. State the skeleton first; the lemmas fall out for free. |
"Adding | They are redundant to the kernel and essential to every human or model that reads the proof next. |
| "This helper is too specific to be a lemma" | If it has a clean statement, extract it — dropping the hypotheses it doesn't need usually reveals it was general all along. |
| "We'll add linters once the library stabilizes" | Backwards: patterns propagate by copy-paste, so a deferred linter meets a 400-warning backlog instead of one bad line. Enable what is already clean and gate it now. |
| "The check passed, so we're clean" | A check that can't fail proves nothing — sweeps reach zero files, misspelled |
| "The proof is slow, raise maxHeartbeats" | An unmeasured budget is a claim, not a fix — and it masks the regression the next reader needs to see. Measure with |
| 借口 | 真相 |
|---|---|
| “证明能编译,直接发布” | 能编译只是最低要求。只有Lean能读懂的单片策略块会在下次Mathlib更新时静默失效,且无人能修复。 |
| “展开定义比编写API引理更简单” | 每个下游 |
| “压缩每个simp能让证明更快更健壮” | 对于末尾的simp调用来说,这是错误的:压缩后的列表会在每次重命名时失效,且掩盖关键信息。仅压缩非末尾调用。 |
| “更短,因此更好” | Mathlib审阅政策:仅当不牺牲可读性时,简化代码才是可行的。长度不是目标;易读性才是。 |
| “等证明完成后再重构为引理” | 证明完成后,结构会成为支撑性的且相互缠绕。先陈述框架,引理会自然形成。 |
“添加 | 对内核来说是冗余的,但对下一个阅读证明的人类或模型来说是必不可少的。 |
| “这个辅助定理太特殊,不适合作为引理” | 如果它有清晰的陈述,就提炼出来——移除它不需要的假设通常会发现它本来就具有通用性。 |
| “等库稳定后再添加检查器” | 恰恰相反:模式会通过复制粘贴传播,延迟添加检查器会遇到400条警告的积压,而非一条不良代码。现在就启用已符合规范的检查并设置关卡。 |
| “检查通过了,所以我们没问题” | 不会失败的检查毫无意义——扫描结果为零文件、拼写错误的 |
| “证明太慢,提高maxHeartbeats” | 未测量的预算只是一种断言,而非修复——它会掩盖下一位读者需要看到的性能退化。用 |