Lean 4.24.0 (2025-10-14)
本次发布共合入 377 项变更。除下文列出的 105 项功能新增和 75 项修复外,还有 25 项重构、9 项文档改进、21 项性能改进、4 项测试套件改进,以及 138 项其他改动。
亮点
Lean 4.24.0 继续改进模块系统和验证框架,增强了 grind 策略,并推进了标准库的发展。本次发布还引入了更高效的 DecidableEq 实例与 noConfusion 构造(#10152 与 #10300),从而优化编译。
作为我们持续改进性能的一个例子:
-
#10249 通过改进语言服务器的多处性能表现,将自动补全速度提升到了约 3.5 倍。
和往常一样,本次也包含大量错误修复和新特性,下面列出其中一部分:
“try this” 建议显示在 “Messages” 下方
-
#9966 调整了 “try this” 小部件的呈现方式:它现在会作为 Messages 下方的一条小部件消息显示,而不是作为 Suggestions 区域下的独立小部件显示。这样做的主要好处是,这条消息不再会在 Messages 和 Suggestions 之间重复出现。
mvcgen 中的 invariants 与 with 小节
-
#9927 为
mvcgen实现了受induction启发的扩展语法,允许可选的invariants和with小节。
下面的示例证明了 nodup 能正确检查列表中的重复元素。
import Std.Tactic.Do
import Std
open Std Do
def nodup (l : List Int) : Bool := Id.run do
let mut seen : HashSet Int := ∅
for x in l do
if x ∈ seen then
return false
seen := seen.insert x
return true
theorem nodup_correct (h : nodup l = r) : r = true ↔ l.Nodup := by
unfold nodup at h
apply Id.of_wp_run_eq h; clear h
mvcgen
invariants
· Invariant.withEarlyReturn
(onReturn := fun ret seen => ⌜ret = false ∧ ¬l.Nodup⌝)
(onContinue := fun xs seen =>
⌜(∀ x, x ∈ seen ↔ x ∈ xs.prefix) ∧ xs.prefix.Nodup⌝)
with grind
库:二进有理数
-
#9993 定义了二进有理数,并证明它们构成一个可嵌入到有理数中的有序环。
grind AC 求解器
grind 现在可以对结合、交换、幂等以及/或者幺元运算进行推理(#10105、#10146 等):
example (a b c : Nat) : max a (max b c) = max (max b 0) (max a c) := by
grind only
example {α} (as bs cs : List α) : as ++ (bs ++ cs) = ((as ++ []) ++ bs) ++ (cs ++ []) := by
grind only
example {α : Sort u} (op : α → α → α) (u : α) [Std.Associative op] [Std.Commutative op] [Std.IdempotentOp op] [Std.LawfulIdentity op u] (a b c : α)
: op (op a a) (op b c) = op (op (op b a) (op (op u b) b)) c := by
grind only
元编程说明
-
#10306 修复了
rw策略中的几个错误。
元编程 API:若要精译重写定理并对表达式应用重写,请优先使用 Lean.Elab.Tactic.elabRewrite,而不是 Lean.MVarId.rewrite。
破坏性变更
-
#9749 将 Lake 代码库全面重构为使用新的模块系统。
Lake中的每个模块现在都是真正的module。破坏性变更: 由于模块系统鼓励采用“默认
private”的设计,Lake API 已从先前“默认public”的做法切换过来。因此,许多以前公开的定义现在都变成了私有。预计这些新变为私有的定义不会被用户大量使用,但仍可能遗漏重要用例。如果某个关键 API 现在无法访问、但看起来本应公开,鼓励用户在 GitHub 上提交 issue 反馈。
语言
-
#8891 改进把(自动冗余的)局部假设传给
grind时产生的错误消息。 -
#9651 修改了通过
partial_fixpoint定义的mutual块所生成的归纳引理与部分正确性引理。此外,还修改了通过mutual块为函数生成格论归纳原理的方式,使其与partial_fixpoint保持一致。 -
#9674 在精译定义体、定理体、
fun体和let函数体之前,会先清理optParam/autoParam等注解。声明头中的variable与绑定器都受支持。 -
#9918 防止
rcases和obtain在拆解单构造器类型(如Exists)时生成荒谬冗长的分支标签名。修复 #6550。 -
#9923 为一个会导致 doc-gen4 崩溃的反精译器添加了防护。这目前只是权宜之计,@sgraf812 休假回来后会进一步检查。
-
#9926 为
Std.Tactic.Do.MGoalEntails反精译器添加检查,确保至少存在三个参数,从而防止潜在崩溃。 -
#9927 为
mvcgen实现了扩展的、受induction启发的语法,允许可选的using invariants与with小节。 -
#9930 回退了
grind cutsat将Nat.sub嵌入Int的方式。它修复了 David Renshaw 在 Zulip 上报告的一个回归。 -
#9938删除了重复的
mpure_intro策略定义。 -
#9939 将
mvcgen using invariants | $n => $t展开为mvcgen; case inv<$n> => exact $t,以避免在 #9581 的测试用例中可观察到的 MVar 实例化失误。 -
#9942 修改
intro,为每个假设创建局部化的策略信息,从而可以逐个变量地看出intro的工作方式。此外:-
该策略现在支持
intro rfl:它会像rintro rfl一样引入一个等式并立即代换(回顾一下,rfl模式相当于执行intro h; subst h)。如果eq_of_heq适用,rintro现在也支持在rfl模式中处理HEq。 -
在
intro (h : t)中,t的精译会与同h的类型做统一交错进行,从而避免默认实例导致统一失败。 -
会改变假设类型的策略(包括
intro (h : t)、delta、dsimp)现在会更新局部实例缓存。
-
-
#9945 优化
grind cutsat生成的证明项。它会在构造最终证明时移除上下文对象中未使用的条目,从而显著减少结果项里的冗余内容。示例:/-- trace: [grind.debug.proof] fun h h_1 h_2 h_3 h_4 h_5 h_6 h_7 h_8 => let ctx := RArray.leaf (f 2); let p_1 := Poly.add 1 0 (Poly.num 0); let p_2 := Poly.add (-1) 0 (Poly.num 1); let p_3 := Poly.num 1; le_unsat ctx p_3 (eagerReduce (Eq.refl true)) (le_combine ctx p_2 p_1 p_3 (eagerReduce (Eq.refl true)) h_8 h_1) -/ #guard_msgs in -- Context should contain only `f 2` open Lean Int Linear in set_option trace.grind.debug.proof true in example (f : Nat → Int) : f 1 <= 0 → f 2 <= 0 → f 3 <= 0 → f 4 <= 0 → f 5 <= 0 → f 6 <= 0 → f 7 <= 0 → f 8 <= 0 → -1 * f 2 + 1 <= 0 → False := by grind -
#9946 优化
grind ring生成的证明项。它与 #9945 类似,但面向grind中的 ring 模块;在生成最终证明时,会从上下文对象中移除未使用的条目,从而显著减少结果项里的冗余内容。示例:/-- trace: [grind.debug.proof] fun h h_1 h_2 h_3 => Classical.byContradiction fun h_4 => let ctx := RArray.branch 1 (RArray.leaf x) (RArray.leaf x⁻¹); let e_1 := (Expr.var 0).mul (Expr.var 1); let e_2 := Expr.num 0; let e_3 := Expr.num 1; let e_4 := (Expr.var 0).pow 2; let m_1 := Mon.mult (Power.mk 1 1) Mon.unit; let m_2 := Mon.mult (Power.mk 0 1) Mon.unit; let p_1 := Poly.num (-1); let p_2 := Poly.add (-1) (Mon.mult (Power.mk 0 1) Mon.unit) (Poly.num 0); let p_3 := Poly.add 1 (Mon.mult (Power.mk 0 2) Mon.unit) (Poly.num 0); let p_4 := Poly.add 1 (Mon.mult (Power.mk 0 1) (Mon.mult (Power.mk 1 1) Mon.unit)) (Poly.num (-1)); let p_5 := Poly.add 1 (Mon.mult (Power.mk 0 1) Mon.unit) (Poly.num 0); one_eq_zero_unsat ctx p_1 (eagerReduce (Eq.refl true)) (Stepwise.simp ctx 1 p_4 (-1) m_1 p_5 p_1 (eagerReduce (Eq.refl true)) (Stepwise.core ctx e_1 e_3 p_4 (eagerReduce (Eq.refl true)) (diseq0_to_eq x h_4)) (Stepwise.mul ctx p_2 (-1) p_5 (eagerReduce (Eq.refl true)) (Stepwise.superpose ctx 1 m_2 p_4 (-1) m_1 p_3 p_2 (eagerReduce (Eq.refl true)) (Stepwise.core ctx e_1 e_3 p_4 (eagerReduce (Eq.refl true)) (diseq0_to_eq x h_4)) (Stepwise.core ctx e_4 e_2 p_3 (eagerReduce (Eq.refl true)) h)))) -/ #guard_msgs in -- Context should contains only `x` and its inverse. set_option trace.grind.debug.proof true in set_option pp.structureInstances false in open Lean Grind CommRing in example [Field α] (x y z w : α) : x^2 = 0 → y^2 = 0 → z^3 = 0 → w^2 = 0 → x = 0 := by grind -
#9947 优化
grind linarith生成的证明项。它与 #9945 类似,但面向grind中的linarith模块;在生成最终证明时,会从上下文对象中移除未使用的条目,从而显著减少结果项里的冗余内容。 -
#9951 为所有归纳类型生成
.ctorIdx函数,而不仅限于枚举类型。这可以作为其他构造(如BEq、noConfusion)的基础,使它们即便面对大型归纳类型也能保持尺寸高效。 -
#9952 添加“非分支式分情况语句”:对每个归纳类型构造器
T.con,新增一个与T.casesOn类似的函数T.con.with,但它只有一个分支(即con的分支),并额外带有假设t.toCtorIdx = 12。 -
#9954 删除了选项
grind +ringNull。它为grind ring模块提供了另一种证明项构造方式,但效果不如默认模式,实际上已经成了死代码。该 PR 还利用 #9946 中加入的基础设施,优化了半环归一化证明项。备注: 在更新第 0 阶段之后,我们可以删除Init/Grind目录中的若干背景定理。 -
#9958 确保
grind cutsat模块中的方程始终保持已解形式。也就是说,若用方程a*x + p = 0消去x,则线性多项式p中不得再包含其他已消去的变量。在这个 PR 之前,这些方程保持的是三角形式。我们接下来会利用已解形式来线性化非线性项。 -
#9968 修改了实现非原子定义与
$cmd1 in $cmd2语法的宏。这些宏涉及由section和namespace命令引入的隐式作用域。由于小节与命名空间本来就是用来界定局部属性的,把局部属性应用到上述上下文中出现的定义时,会产生不直观的行为;这正是下面这些示例失败的原因:axiom A : Prop
-
#9974 为
Lean.Parser.Command.visibility注册了解析器别名。这样一来,使用可见性修饰的简单命令宏就不必再导入Lean.Parser.Command。 -
#9980 修复了
grind cutsat所用动态变量重排函数中的一个错误。 -
#9989 将
mvcgen的新扩展语法改为mvcgen invariants ... with ...。 -
#9995 几乎完全重写了归纳谓词递归算法,尤其让
IndPredBelow的行为更加一致。历史上,经由IndPredBelow生成brecOn一直很容易出错;现在这一问题应已修复,因为新算法非常直接,完全不依赖策略或元变量。此外,归纳谓词的新结构递归过程与常规结构递归共享了更多代码,因此现在也能像常规结构递归那样支持互递归和嵌套递归。例如,下面的代码现在可以工作:mutual
-
#9996 改进了
grind cutsat对非线性单项式的支持。例如,给定单项式a * b,如果cutsat发现a = 2,它现在会传播出a * b = 2 * b。回顾一下,a * b这样的非线性单项式在cutsat中被当作变量,而 cutsat 是为线性整数算术设计的过程。 -
#10007 让 #print 在输出
protected之前先输出private,与语法保持一致。 -
#10008 修复了
#eval的一个错误:点击求值后的表达式时,Infoview 可能显示错误。这是因为#eval在精化该表达式时没有保存所用的临时环境。 -
#10010 改进了
grind cutsat对非线性/和%的支持。例如,给定a / b,如果cutsat发现b = 2,它现在会传播出a / b = b / 2。这与 #9996 类似,不过针对的是/和%。示例:example (a b c d : Nat) : b > 1 → d = 1 → b ≤ d + 1 → a % b = 1 → a = 2 * c → False := by grind -
#10020 为 PR #10010 补上了一个遗漏的分支。
-
#10021 对 grind 标注分析脚本做了一些小改动,包括结果排序与错误处理;外部 UI 仍有待添加。
-
#10022 改进了
grind cutsat在n不是数值字面量时对Fin n的支持。例如,下面的目标现在可以自动求解:example (p d : Nat) (n : Fin (p + 1)) : 2 ≤ p → p ≤ d + 1 → d = 1 → n = 0 ∨ n = 1 ∨ n = 2 := by grind -
#10034 修改了 “declaration uses 'sorry'” 错误,使其在消息中美观打印实际的
sorry表达式。这样一来,sorry就可以被悬停查看;如果它带有标签,你还可以“转到定义”来查看其来源。 -
#10038 确保
grind错误消息在引用声明名时使用{.ofConstName declName}。 -
#10060 让模块系统下“哪些派生实例拥有暴露定义”可以被更细粒度地控制:处理器不应暴露其实现,除非派生项本身或外围的 section 之一被标记为
@[expose]。内建处理器会在第 0 阶段更新后跟进调整。 -
#10069 为
grind linarith添加了支持NatModule的辅助定理。 -
#10071 改进了
grind cutsat对a^n的支持。例如,如果cutsat发现a和b都等于某个数值字面量,它现在会传播相应的等式。这与 #9996 类似,不过处理的是a^b。示例:example (n : Nat) : n = 2 → 2 ^ (n+1) = 8 := by grind
-
#10085 为
rawIdent解析器添加了解析器别名,使它可以用于Init中的syntax声明。 -
#10093 为
grind中一个即将实现、支持结合与交换运算符的新求解器添加了背景定理。 -
#10095 修改
grind的代数类型类,使其使用SMul x y取代HMul x y y。 -
#10105 为
grind增加了检测结合运算符的能力。新的 AC 模块还会检测该运算符是否满足交换性、幂等性,以及是否具有中性元;这些信息都会被缓存。 -
#10113 弃用
.toCtorIdx,改用命名更自然的.ctorIdx(并同步更新标准库)。 -
#10120 修复了一个问题:使用广义字段记号(点记号)递归调用私有定义时,会报出 “invalid field” 错误。它还修复了另一处问题:invalid field notation 错误会把声明名带着
_private前缀一起美观打印出来。 -
#10125 允许
#guard_msgs通过配置选项(positions := true)报告已记录消息的相对位置。 -
#10129 将
Grind使用的临时序类型类替换为Std中新公开的类型类。 -
#10134 让函数归纳原理的生成在用户使用
let绑定某个随后会被match的变量时更稳健。修复 #10132。 -
#10135 让单构造器归纳类型的
ctorIdx定义可以避开无意义的.casesOn,并使用macro_inline以避免编译该函数并浪费符号。 -
#10141 回退了 #10135 中关于
macro_inline的那部分改动。 -
#10144 修改了
coinductive_fixpoint/inductive_fixpoint机制中对谓词(即映到Prop的函数)构造CompleteLattice实例的方式。 -
#10146 为
grind中处理 AC 运算符的新过程实现了基础设施。它已经支持对不等性进行归一化;未来的 PR 将增加基于等式做化简以及计算临界对的支持。示例:example {α : Sort u} (op : α → α → α) [Std.Associative op] (a b c : α) : op a (op b c) = op (op a b) c := by grind only -
#10151 确保在模块系统下,
where finally策略只要对应的占位都属于命题类型,即使这些占位位于公开作用域,也仍然可以访问私有数据。 -
#10152 为
DecidableEq实例引入了另一种构造方式,从而避免默认构造的二次开销。 -
#10166 重新审视了
grind当前预期失败的测试:把一些现在已经通过的测试移入主测试套件,更新了一些测试,并增加了若干关于指数归一化的测试。 -
#10177 修复了 #10160 暴露出来的
grind预处理器错误。 -
#10179 修复了 grind 的实例归一化过程。
grind中有些模块直接使用核心中定义的内建实例(如cutsat),而另一些模块则通过synthInstance合成实例(如ring)。这种不一致会引入不匹配,并让同一项出现两种不同表示;该 PR 解决了这一问题。 -
#10183 让匹配方程在可能时直接用
rfl证明,而不是先显式展开左侧;这可能生成更小的证明。 -
#10185 为
grind的全部属性修饰符补充了文档(如=、usr、ext等)。 -
#10186 为
grind ac模块添加了化简不等式的支持。 -
#10189 为新的
grind ac模块实现了证明项。示例:example {α : Sort u} (op : α → α → α) [Std.Associative op] (a b c d : α) : op a (op b b) = op c d → op c (op d c) = op (op a b) (op b c) := by grind only -
#10205 为
grind ac中的结合且交换运算符添加了超位推理支持。示例:example (a b c d e f g h : Nat) : max a b = max c d → max b e = max d f → max b g = max d h → max (max f d) (max c g) = max (max e (max d (max b (max c e)))) h := by grind -cutsat only -
#10206 为
grind ac中的结合但非交换运算符添加了超位推理支持。示例:example {α} (op : α → α → α) [Std.Associative op] (a b c d : α) : op a b = c → op b a = d → op (op c a) (op b c) = op (op a d) (op d b) := by grind -
#10208 添加了额外的临界对,以确保当运算符同时满足结合性、交换性和幂等性时,
grind ac过程仍然完备。示例:example {α : Sort u} (op : α → α → α) [Std.Associative op] [Std.Commutative op] [Std.IdempotentOp op] (a b c d : α) : op a (op b b) = op d c → op (op b a) (op b c) = op c (op d c) := by grind only -
#10221 添加了额外的关键对,以确保当运算符具有结合性和幂等性但不具有交换性时,
grind ac过程仍然完备。示例:example {α : Sort u} (op : α → α → α) [Std.Associative op] [Std.IdempotentOp op] (a b c d e f x y w : α) : op d (op x c) = op a b → op e (op f (op y w)) = op a (op b c) → op d (op x c) = op e (op f (op y w)) := by grind only -
#10223 实现了把新 AC 模块中的等式传播到
grind核心。示例:example {α β : Sort u} (f : α → β) (op : α → α → α) [Std.Associative op] [Std.Commutative op] (a b c d : α) : op a (op b b) = op d c → f (op (op b a) (op b c)) = f (op c (op d c)) := by grind only -
#10230 为更多单子变换器添加了
MonoBind。这使partial_fixpoint可以用于基于Option和EIO的更复杂单子。示例:abbrev M := ReaderT String (StateT String.Pos Option)
-
#10237 修复了
grind规范化器中的一个缺失分支。有些类型可能包含稍后才会被内部化到grind状态中的项或命题。 -
#10239 修复了针对含有未被常规参数引用的宇宙参数之定理的 E-匹配过程。这类定理在实践中不常见,但标准库中确实存在。示例:
@[simp, grind =] theorem Std.Do.SPred.down_pure {φ : Prop} : (⌜φ⌝ : SPred []).down = φ := rfl -
#10241 添加了一些
grind配合Fin工作的测试用例。tests/lean/grind/grind_fin.lean中仍有许多失败测试,我打算继续分拣和处理。 -
#10245 修改了(协)归纳谓词机制中使用的函数
unfoldPredRel的实现,它会把谓词上的逐点序展开为量化与蕴含。此前的实现依赖withDeclsDND,而它无法处理互相依赖的类型。这导致下面的示例失败:inductive infSeq_functor1.{u} {α : Type u} (r : α → α → Prop) (call : {α : Type u} → (r : α → α → Prop) → α → Prop) : α → Prop where | step : r a b → infSeq_functor1 r call b → infSeq_functor1 r call a -
#10265 修复了 #10242 暴露出来的
grind ring崩溃。grind ring不应假定所有归一化都已经完成,因为受类型约束所限,simp无法改写某些子项。此外,grind在少数地方会使用preprocessLight,而它会跳过简化器/归一化器。 -
#10267 实现了在
grind linarith中支持NatModule的基础设施,并用它处理不等性。后续 PR 还会增加对等式与不等式的支持。示例:open Lean Grind variable (M : Type) [NatModule M] [AddRightCancel M]
-
#10269 修改了字符串插值过程,使其省略冗余的空片段。例如,
s!"{1}{2}"过去会精译成toString "" ++ toString 1 ++ toString "" ++ toString 2 ++ toString "",现在则会精译成toString 1 ++ toString 2。 -
#10271 修改了 BEq 这类派生实例内部函数的命名方式,使其使用可访问的名称。这样更便于对这些函数进行证明。例如,对类型
T执行deriving BEq之后,instBEqT的实现位于instBEqT.beq。 -
#10273 尝试正确处理 same-ctor-match 结构的可见性。
-
#10274 修改了线性
DecidableEq实现的写法:在比较构造器标签时改用match decEq,而不是if h :。否则,“智能展开”机制无法让rfl判定不同构造器彼此不同。 -
#10277 为
OfNatModule.Q α补上了缺失的IsPartialOrder、IsLinearPreorder与IsLinearOrder实例。 -
#10278 在
grind linarith中加入了对NatModule等式与不等式的支持。示例:open Lean Grind Std
-
#10280 添加了辅助定理
Lean.Grind.Linarith.eq_normN,用于在AddRightCancel实例不可用时归一化NatModule等式。 -
#10281 在
AddRightCancel实例不可用时实现了NatModule的归一化。请注意,此时嵌入到IntModule并不是单射。因此,我们使用了一个自定义归一化器,类似于grind ring模块中CommSemiring所用的归一化器。示例:open Lean Grind example [NatModule α] (a b c : α) : 2•a + 2•(b + 2•c) + 3•a = 4•a + c + 2•b + 3•c + a := by grind -
#10282 改进了
grind linarith为NatModule生成的反例。grind现在会隐藏辅助函数Grind.IntModule.OfNatModule.toQ的出现。 -
#10283 为
grind ac模块实现了诊断信息。它现在会显示基、归一化后的不等性,以及为每个结合运算符检测到的附加性质。 -
#10290 为注册新的
grind求解器增加了基础设施。grind已经包含许多求解器,而这个 PR 是迈向模块化设计和支持用户自定义求解器的第一步。 -
#10294 完成了
grind求解器扩展机制的设计,并将grind ac求解器迁移到新框架。未来的 PR 会为 API 补充文档,并迁移其余求解器。新设计的另一项好处是构建时间更快。 -
#10296 修复了
grind cutsat中一个用于构造证明项的辅助函数错误。 -
#10300 为
noConfusion的非对角用法(也就是不同构造器之间的情形)提供了另一种基于比较.ctorIdx的构造方式。这应当会带来更快的类型检查,因为内核只需约化.ctorIdx两次,而不必处理复杂的noConfusionType构造。 -
#10301 暴露了 ctorIdx 以及按构造器区分的消去器。修复 #10299。
-
#10306 修复了
rw策略中的几个错误:它此前可能因为目标出现在重写类型里而“偷走”目标,也没有执行出现检查,且新生成的证明目标不会是合成不透明的。该 PR 还让rfl策略能够给合成不透明元变量赋值,从而与exact rfl等价。 -
#10307 将 Verso 解析器上游合入,并为在文档字符串中使用 Verso 添加了初步支持。这将允许编译器检查文档里的示例和交叉引用。
-
#10309 修改了
simpa策略,使得在simpa ... using e中,范围simpa ... using上会附带策略信息,以显示化简后的目标。 -
#10313 为
natCast和intCast添加了缺失的grind归一化规则。示例:open Lean.Grind variable (R : Type) (a b : R)
-
#10314 会在实例上跳过基于模型的理论组合。
-
#10315 添加了
T.ctor.noConfusion声明,它们是T.noConfusion在T.ctor之间等式上的特化。目的是避免每次使用injection或类似策略时都去约化T.noConfusionType的构造。 -
#10316 共享了处理同一构造器之间等式以及判断这些等式类型是否正确的通用功能。具体而言,它也在
CasesOnSameCtor以及BEq、DecidableEq、Ord的派生代码等位置使用mkInjectivityThm中更完整的逻辑,从而提升一致性并改进错误消息。 -
#10321 确保
grind所用 E-匹配模块创建的辅助临时元变量 ID 不受调用grind之前已执行内容的影响,目的是提升grind的稳健性。 -
#10322 为
grind引入功能受限的前端cutsat和grobner。我们禁用了定理实例化(grobner还禁用了分情况拆分),并关闭所有其他求解器。二者仍允许grind的配置项,因此例如可以用cutsat +ring(或grobner +cutsat)解决同时需要两者的问题。 -
#10323 修复了
grind对OfNat.ofNat应用的规范化器。示例:example {C : Type} (h : Fin 2 → C) : -- `0` in the first `OfNat.ofNat` is not a raw literal h (@OfNat.ofNat (Fin (1 + 1)) 0 Fin.instOfNat) = h 0 := by grind -
#10324 禁用了一个会触发昂贵类型类搜索的未使用实例。
-
#10325 为实现
ToInt接口的类型A实现了基于模型的理论组合。示例:example {C : Type} (h : Fin 4 → C) (x : Fin 4) : 3 ≤ x → x ≤ 3 → h x = h (-1) := by grind -
#10326 修复了
grind linarith中的一个性能问题。它此前会为无序的交换环构造多余的NatModule/IntModule结构;这类类型本应只交给grind ring处理。 -
#10331 用 Lean 而不是 C 实现了
mkNoConfusionImp。这减少了我们对 C 的依赖,并可能带来性能收益,因为它避免了在精译期间约化noConfusionType(不过内核在类型检查时仍会约化它)。 -
#10332 确保信息树在
classical策略之下会把Classical.propDecidable识别为实例。 -
#10335 修复了
grind中的嵌套证明项检测;它必须检查工具项Grind.nestedProof是否被过度应用。 -
#10342 实现了新的 E-匹配模式推断过程,使其符合参考手册中关于“最小可索引子表达式”的记录行为。旧的推断过程没有落实这一条件。例如,手册中对
[grind ->]的说明如下。 -
#10373 添加了
pp.unicode选项,以及底层解析器unicodeSymbol "→" "->"的语法说明别名unicode("→", "->")。这一语法也被加入到了notation命令中。当pp.unicode为真(默认值)时,美观打印会使用第一种形式;否则使用第二种 ASCII 形式。变体unicode("→", "->", preserveForPP)会让->形式成为首选;反精译器也可以直接在语法中插入→,并按原样美观打印。这使得fun一类记号能够使用pp.unicode.fun之类的自定义选项,在美观打印时选择 Unicode 形式。
库
-
#7858 实现了用于无符号乘法溢出检测的快速电路;Bitwuzla 采用了这一方案,提出它的论文如下: https://ieeexplore.ieee.org/stamp/stamp.jsp?tp=&arnumber=987767
-
#9127 让
saveModuleData在收到无法序列化的对象时抛出 IO.Error,而不是直接崩溃。这对保存模块本身影响不大,但在编写工具、通过 Batteries 的pickle往 olean 文件里保存辅助数据时很有用。 -
#9560 修复了
forIn函数:此前如果其内部抛出异常,得到的 Promise 会被丢弃而没有值。它还修正了background函数的参数顺序。 -
#9599 添加了类型
Std.Internal.Parsec.Error,其中包含构造器.eof(可用于判断解析是否因为输入不足而失败,从而在输入继续到来时重试,这对 HTTP 服务器很有用)与.other(用于描述其他错误)。它还为许多函数补上了文档,并为ByteArrayParsec 新增了一些函数,如peekWhen?、octDigit、takeWhile、takeUntil、skipWhile与skipUntil。 -
#9632 为
TreeMap的filter、map与filterMap操作添加了引理。这些引理原本已经存在于 HashMap,这里只是把对应内容移植过来。 -
#9685 验证了 HashMap 的
toArray及其相关函数。 -
#9797 提供了一种快速批量给出高层序结构(预序、偏序、线性预序、线序)相关全部序实例的方法,可通过工厂函数
PreorderPackage.ofLE、PartialOrderPackage.ofLE、LinearPreorderPackage.ofLE与LinearOrderPackage.ofLE实现。 -
#9908 让
IsPreorder、IsPartialOrder、IsLinearPreorder与IsLinearOrder视需要扩展BEq和Ord,新增把BEq、Ord同LE关联起来的类型类LawfulOrderBEq与LawfulOrderOrd,并加入了大量引理与实例。 -
#9916 提供了可在给定
Ord实例时批量派生序类型类的工厂。如果已有实例存在,则优先使用现有实例,而不是使用由Ord派生出的实例;如有需要,也可以手动指定任意实例。 -
#9924 修复了
PostCond文档中的示例。 -
#9931 实现了
Std.Do.Triple.mp,使用户可以把同一程序的两个规格组合起来。 -
#9949 让大多数
List.lookup引理在LawfulBEq α不可用时也能使用。 -
#9957 将来自 Batteries 的 Rat 定义上游合入,以供我们计划中的区间算术策略使用。
-
#9967 从 SpecLemmas.lean 中移除了本地
Triple记号,以绕开一个会破坏第 2 阶段构建的错误。 -
#9979 用从 Batteries 上游合入的公共
Rat替换Std.Internal.Rat。 -
#9987 改进了证明基于
Nat的PRange元素满足界限条件的策略,使其改为依赖omega策略。 -
#9993 定义了二进有理数,并证明它们构成一个可嵌入到有理数中的有序环。我们将把它用于未来的区间算术策略。
-
#9999 减少了我们为处理分配律而添加的
Nat.Bitwisegrind标注数量。新的较小标注集会鼓励 grind 重写到 DNF;旧行为只会让实例化很快达到上限。 -
#10000 删除了一条会在所有
Option.map上触发的grind标注,它会造成雪崩式的实例化。 -
#10005 缩短了让某个类型兼容多态区间记号所需的工作量。以
Nat为例,它将所需代码行数从 150 行减少到了 70 行。 -
#10015 暴露了
Name.append、Name.appendCore与Name.hasMacroScopes的定义体。这使得在模块系统下可以通过反射证明名称字面量的拼接。 -
#10018 为
Lean.Import派生了BEq与Hashable。Lake 之前稍后才会这样做;现在在定义Import时就会完成。 -
#10019 为
Lean.ParserState.setPos添加了@[expose]。这使得对setPos产生的状态,为next'和get'之类函数证明有界性时,无需import all。 -
#10024 为
LawfulOrderMin/Max与LawfulOrderLeftLeaningMin/MaxAPI 添加了有用声明。尤其是,它为Min与Max引入了.leftLeaningOfLE工厂,还把LawfulOrderMin/Max.of_le重命名为 .of_le_min_iffand.of_max_le_iff`,并新增了一个参数不同的第二变体。 -
#10045 实现了让区间记号适用于整数所需的类型类。例如,
((-2)...3).toList = [-2, -1, 0, 1, 2] : List Int。 -
#10049 为在 #9993 中引入二进有理数补充了一些所需的背景材料。
-
#10050 修复了 Data/Rat/Lemmas 中的一些命名问题,并将消去器
numDenCasesOn及其相关项上游合入。 -
#10059 改进了多态区间 API 中定义与引理的命名,并引入了推荐写法。例如,左闭右开的区间会参照 Mathlib 中的
Ico记号,写作Rco。 -
#10075 加入了一些关于
Int的引理(以及对 BitVec 和 Nat 的少量修订),它们会用于为二进有理数做准备。这部分工作都来自 @Rob23oba;我把它从 #9993 中提前拆出来,以便让那个 PR 更易于处理。 -
#10077 将
Mathlib.Data.Rat.Defs与Mathlib.Algebra.Order.Ring.Unbundled.Rat中关于Rat的引理上游合入,具体数量足以得到Lean.Grind.Field Rat和Lean.Grind.OrderedRing Rat。除了这些引理外,还上游合入了Inv Rat、Pow Rat Nat与Pow Rat Int的实例。 -
#10107 为
Rat添加了Lean.Grind.AddCommGroup实例。 -
#10138 添加了关于
Dyadic.roundUp与Dyadic.roundDown运算的引理。 -
#10159 为所有
Map变体添加了nodup_keys引理,作为现有distinct_keys的推论。 -
#10162 去掉了会过于频繁、且往往无益地触发的
grind →标注。理想情况下,grind只有在已经看见xs ++ ys与#[]处在同一个等价类中时,才应实例化这些引理,而不是一看到xs ++ ys就立即实例化。 -
#10163 删除了一些(希望确实是)不必要、但会导致实例化爆炸的
grind标注。 -
#10173 从
MonadAwait与MonadAsync中移除了extends Monad,以避免实例欠定。 -
#10182 为
Nat.fold与Nat.foldRev在求和上的行为添加了引理,以匹配现有关于dfold和dfoldRev的定理。 -
#10194 添加了给定精度下二进有理数的逆元及其刻画引理;它还清理了
Int.DivMod与RatAPI 的若干部分,并证明了一些关于Rat.toDyadic的刻画引理。 -
#10216 修复了 #10193。
-
#10224 将
HashMap、TreeMap与HashSet的单子化操作泛化为可适用于m : Type u → Type v。 -
#10227 为
ReaderT、StateT与ExceptT添加了@[grind]标注(几乎全部都是同现有@[simp]平行的@[grind =]标注)。 -
#10244 为区间和迭代器的
toList与toArray函数添加了更多引理,同时将Array.mem_toArray重命名为List.mem_toArray。 -
#10247 为所有容器类型补上了缺失的引理
ofList_eq_insertMany_empty、get?_eq_some_iff、getElem?_eq_some_iff与getKey?_eq_some_iff。 -
#10250 修复了
LinearOrderPackage.ofOrd工厂中的一个错误。如果有LawfulEqOrd实例可用,它应自动使用它,而不是要求用户向工厂提供eq_of_compare参数。该 PR 还解决了一个与卫生相关的问题:当Std未打开时,这些工厂会失败。 -
#10303 为
BitVec与UInt*类型加入了区间支持。这意味着现在可以写出例如for i in (1 : UInt8)...5 do这样的代码,以遍历类型为UInt8的值 1、2、3 和 4。 -
#10341 将
Function.Injective与Function.Surjective的定义和基本事实从 Mathlib 上游合入。有了这些内容后,我们在grind中基于单射性进行推理时可以做得更好。
编译器
-
#9631 让
IO.RealWorld变为不透明。它还新增了一个仅供编译器使用的常量lcRealWorld,用于在编译器内部表示该类型。默认情况下,不透明类型定义会被当作lcAny处理,而这里我们希望得到更高效的表示。目前差别还不大,但未来我们希望在运行时把IO.RealWorld完全抹除。 -
#9922 修改了
internalizeCode:它会把Expr中(这些位置全都是类型)所有带有非参数绑定自由变量的替换项都替换为lcAny,从而保持“不存在此类依赖”的不变式。这个不变式在文件之间被破坏曾导致一个待合并 PR 中的测试失败,但很难为它写出直接测试。未来我们或许应当让 LCNF 检查器能够检测这一点。 -
#9972 修复了把 Mathlib 的
FintypeCat当作代码运行时出现的一个问题:某个被擦除的类型构造器会被传给多态函数。此前我们把箭头类型下调为object,这会与运行时把被擦除值表示为带标签标量的方式发生冲突。 -
#9977 增加了对子单例谓词之
casesOn递归器的编译支持。 -
#10023 添加了支持,以正确处理支持大消去的归纳谓词在
casesOn上的字段计算。对这类谓词,唯一允许的相关字段是同时也被用作索引的那些,此时我们可以找到给定的索引并改用那个项。 -
#10032 修改了在把 LCNF 下调到 IR 时对过度应用构造器的处理方式:从(稍显隐式的)断言失败改为生成
unreachable。对内联的不可达代码做变换时,可能会产生带额外参数的构造器应用。 -
#10040 修改了
toMono阶段:它会用声明的_redArg等价物替换原声明,因此在进行noncomputable检查时,不再把被reduceArity阶段判定为无用的参数纳入考虑。 -
#10070 修复了
noConfusion的编译问题,补上了从旧编译器移植这段代码时遗漏的一点:旧编译器只会针对所讨论归纳类型的每个非Prop输入字段反复展开主参数,这与noConfusion自身的构造相呼应;而新编译器此前错误地统计了所有字段。 -
#10133 修复了 Lean 生成的可执行文件在 Windows 上对 Unicode 文件系统路径的兼容性。
-
#10214 修复#10213。
-
#10256 修正了
toIR中的一个错误:它可能会过度应用某个具有 IR 声明、但没有 mono 声明的函数。 -
#10355 修改了
toLCNF,使其把内建类型上的.proj转换为改用投影函数。
美观打印
-
#10122 增加了使用广义字段记号(点记号)来美观打印公有类型上的私有定义之支持。它还修改了点记号的精译方式:在去掉私有前缀后再解析名称,从而允许对私有导入类型上的私有定义使用点记号。
-
#10373 添加了
pp.unicode选项,以及底层解析器unicodeSymbol "→" "->"的语法说明别名unicode("→", "->")。这一语法也被加入到了notation命令中。当pp.unicode为真(默认值)时,美观打印会使用第一种形式;否则使用第二种 ASCII 形式。变体unicode("→", "->", preserveForPP)会让->形式成为首选;反精译器也可以直接在语法中插入→,并按原样美观打印。这使得fun一类记号能够使用pp.unicode.fun之类的自定义选项,在美观打印时选择 Unicode 形式。 -
#10374 添加了选项
pp.piBinderNames与pp.piBinderNames.hygienic。启用pp.piBinderNames后,非依赖的 Π 绑定器名称会被美观打印出来,而不再省略;当pp.piBinderNames.hygienic为假(默认值)时,只会美观打印其中非卫生的这类绑定器名称。若未显式设置,pp.all会启用pp.piBinderNames。
文档
-
#9956 为
let与have策略的文档字符串补充了更多信息,包括不透明性、各自适用时机以及相关策略。
服务器
-
#9966 调整了 “try this” 小部件的呈现方式:它现在会作为 Messages 下方的一条小部件消息显示,而不是作为 Suggestions 区域下的独立小部件显示。这样做的主要好处是,这条消息不再会在 Messages 和 Suggestions 之间重复出现。
-
#10047 确保悬停在
match上时会显示该 match 的类型。 -
#10052 修复了一个错误:它会导致 Lean 服务器的进程树在关闭 VS Code 后仍然存活。
-
#10249 通过语言服务器中的多项性能改进,把自动补全速度提升到了约 3.5 倍。在某台机器上,
import Mathlib后补全i过去需要 3200ms,现在则只需 920ms。