prover 设计
prover 包把一个定理脚本变为三种结果之一:内核定理、结构化失败,或未完成证明。本页解释该结果模型、分支块如何在策略层之上被调度,以及该包为何采用失败即关闭 (fail closed):没有任何路径能在没有所述目标的内核定理时报告成功。
设计目标
- 端到端运行定理脚本:解析、安装前奏、降级目标、执行步骤、调度分支块。
- 准确告诉用户证明在何处停止:定理、步骤编号、分支路径、源文本、当前目标和局部假设。
- 绝不把内核
Thm之外的任何东西呈现为证明。不受支持的输入、失败的步骤和 hole 都如实报告。 - 通过发布测试所运行、手册所引用的脚本语料 (corpus),保持文档诚实。
数学背景
作为和类型的结果
对于目标为 的脚本,结果为
这三种情形互不相交,且只有第一种携带定理。特别地,未完成证明不是带有额外假设的定理:它是一份报告,包含 hole 所代表的目标 。把 hole 变成假设会得到定理 ,那与用户所要求的是不同的命题。
作为嵌套证明的分支块
后面跟着分支块的步骤,例如 split { s₁ } { s₂ },会在当前目标 上运行该步骤,产生子目标 。每个块 随后是 的一个独立证明:
证明器在以 为根的全新证明状态中运行 (ps_isolate_pending_at),从该状态中得到 的定理 ,并在父状态中用 关闭 。由于父状态中 split 的论证 (justification) 有效,这些定理组合成 的定理;这就是策略设计中所述的论证的 LCF 组合,只是上升了一层。
设计决策
三路结果,而非 Result
问题。 Result[Thm, Error] 会迫使未完成证明要么是定理(这是错的),要么是错误(这会丢掉“错误”与“尚未完成”的区别)。
选择。 ProverRunResult 有三个构造子。prove_theorem_script 仍为只想要定理的调用者返回 Result,但其错误一侧 ProverScriptError 把失败与未完成证明区分开来。
原因。 编辑器和命令行工具对这些情形的处理不同:错误会让用户停下,而未完成证明是带有待处理目标的警告。规范要求 hole 绝不产生定理权限;类型使得这一点不可能被弄错。
诊断携带位置与上下文
每个失败和未完成报告都记录定理名称、步骤索引、分支路径、该步骤的跨度和源文本,以及当时的目标和局部变量,全部以原始输入为准。cmd 包直接打印这些字段。代价是记录较宽;好处是任何使用者都无需重新运行任何东西即可解释结果。
分支块的隔离框架
问题。 在父状态内运行分支体,会让一个分支中的失败干扰其兄弟分支的簿记,并使所报告的分支路径依赖于调度细节。
选择。 每个分支体在其自己的、由一个待处理目标构建的证明状态中运行,不带父状态的重放上下文。当分支体结束时,ps_close_frame 必须返回该目标的定理;父状态用它关闭目标。留有未关闭目标的分支体在该分支步骤处失败。
原因。 这样每个块都是其子目标的独立证明,正如块语法所暗示的那样;并且无论嵌套如何,步骤索引和分支路径都按阅读顺序分配。
坏定理之后文件继续
问题。 含多个定理的文件应报告所有问题,而不只是第一个。
选择。 prove_theorem_file_results_detailed 运行每个定理,并各返回一项。只有无法解析的文件或前奏安装失败才会使整个文件失败。已证明的定理不会加入状态:后面的定理不能按名称引用前面的定理。
原因。 报告每个定理正是 CLI 用户所期望的。不把定理加入状态,使可引用名称的目录保持固定,正如用户手册所述;定理环境不属于已发布子集。
前奏由选项安装
当 auto_install_prelude 开启(默认如此)时,证明器在运行前安装命题前奏。脚本便可使用 T、F 和目录定理而无需准备状态。需要特定状态的测试会将其关闭并自行安装常量。
语料即代码
手册和本页所引用的脚本是 corpus.mbt 中的值:包括正例、反例、未完成和量词用例,每个用例都带有标识符及其所展示的能力或失败,另有从用例到文档锚点的映射矩阵。测试运行每个用例并检查映射,因此已发布的示例不会偏离代码的实际行为。符合性指南 (conformance guide) 把这条规定为公开示例的规则。
正确性与不变量
- 失败即关闭 (fail closed)。
Proved只在一处构造,来自ps_qed的结果,而ps_qed仅在策略层对照根目标检查之后才返回定理。其他每条路径都返回Failed或Unfinished。 - 无权限。 该包调用解析器、策略层和内核状态函数;它自身不构建定理。
- hole 不会泄漏。 hole 会在
ps_qed之前终止脚本;没有任何代码路径能把未完成状态变成定理。 - 位置是原始的。 报告中的偏移和跨度通过解析器的偏移映射,指向所给定的输入字符串。
- 顺序。 文件报告中的各项按源码顺序排列,步骤索引在分支块之间按阅读顺序计数。
被否决的替代方案
- 用异常表示失败。 Result 让每种结果都体现在类型中,并使 CLI 能统一渲染所有结果。
- 把 hole 当作假设。 被拒绝,因为如上所示,所得定理陈述的将不是目标。
- 分支体共享一个状态。 实现更简单,但会耦合兄弟分支,并使归咎依赖于调度。
- 跨文件的定理环境。 让后面的定理引用前面的定理,需要规范尚未定义的命名与重放规程;在此之前,目录是名称的唯一来源。
边界
- 证明器不增加步骤;步骤集合就是 tactics 的步骤加上
hole。 - 它不读取文件也不打印;这由 cmd 包完成。
- 它不搜索证明、不重写也不化简。research_rewrite 中的研究原型并未接入。
- 它不存储已证明的定理,也不让脚本相互引用。