概率编程听起来像是一段普通的代码,但其实它每次运行都要在连续分布上反复抽样、比较、积分。对于很多研究者和工程师来说,这门语言最大的痛点不是写不出来,而是\u201c算不动\u201d:连续值的密度函数是无穷维的,任何想\u201c枚举\u201d它的尝试都会被现实逼退。
2026 年 8 月,一篇由 Wu、Jacobs、Batz、Silva 合作的长文给出了一种看似反直觉的解法:让编译器\u201c沿着比较点把连续值切分\u201d,变成有限个可枚举片段。这个被命名为 Slice 的类型驱动变换,能够把看似无穷的连续程序翻译成纯离散的等价程序——然后交给 Dice、Roulette、Storm 这样的精确离散推理引擎运行。
一、概率程序卡在哪里
概率程序可以看作普通程序加上一对原语:sample(从某个分布抽样)和 observe(拿观察值去修正分布)。当所有分布都是离散表时,推理原则上可以枚举每一种可能;但只要出现一个高斯、指数或任何连续分布,推理空间立刻从有限跳到无穷——这正是现代概率编程最棘手的难题。
传统离散推理引擎(基于决策图、命题逻辑或符号化概率程序)只能在完全离散的世界里工作。它们跑得快、能给精确答案,但前提是输入程序本身就是离散的。问题来了:现实世界是连续的,而工程上又想要离散引擎的速度和精确度。
二、为什么\u201c类型\u201d是关键线索
直觉上,连续值没法被枚举是因为它的取值无穷。但程序员的真正诉求很少是要\u201c知道这个连续值到底等于多少\u201d,而是\u201c它在和哪些常量比较\u201d。只要程序里所有针对这个连续值的比较都只针对有限个常量,那么无穷的取值空间就可以被这些比较点切成有限个区域。
这就是 Slice 的核心洞察:用一个非局部的、类型驱动的静态分析,去扫描整个程序、判断某个连续变量会和哪些常量比较、再据此把它\u201c切\u201d成有限个\u201c观察等价\u201d的区间。这一步看似简单,实际需要全程序视野——只有类型系统能把所有比较点串起来。
三、Slice 的工作流程
Slice 不是一个简单的优化 pass,它更像是把整个程序重写成一个等价但完全离散的版本。第一阶段:类型推断器沿着递归结构和高阶抽象,把每个连续值的\u201c使用拓扑\u201d收集起来;第二阶段:在拓扑里识别出会触发分支决策的所有比较常量;第三阶段:基于这些常量把连续分布切分成若干不相交的片段;第四阶段:把所有 sample 与比较改写为对这些片段的离散枚举操作。
最终得到的程序不再需要采样高斯——它直接枚举每一个由比较点定义的小区间,给每个区间一个权重,让后端用决策图、命题逻辑或其它精确离散算法算下去。整条流水线最奇妙的地方在于:原程序和变换后程序对任何布尔查询都给出完全相同的答案。
四、为什么必须是非局部的
读者可能会问:能不能在每个比较点都做一次\u201c局部切分\u201d?答案是\u201c不行\u201d。因为一段代码可能在函数 a 里被比较一次,在函数 b 里又被比较第二次,局部视野无法判断两次比较是落在同一个区间还是不同区间。只有\u201c沿着类型流把所有比较点串成一张图\u201d,才能给出正确的离散化粒度。
这种\u201c非局部 + 类型驱动\u201d的组合在传统编译器里相对少见,但在依赖类型、效应系统、概率类型论里其实早有伏笔。Slice 的贡献是把这一思路从\u201c理论可能\u201d推到\u201c工程可实现\u201d。
五、证明难在哪里
把一个连续程序翻成一个离散程序容易,但要证明\u201c两者等价\u201d却极难。Slice 用的是耦合式逻辑关系(coupling-style logical relations)论证:构造一个概率耦合,证明原程序与变换后程序在任何观察序列下都保持相同的边际分布。这种论证比简单的\u201c展开看看\u201d严谨得多,也是论文最值得花时间读的技术部分。
另一个工程难点:原程序可能递归、可能高阶、可能依赖闭包捕获。离散化必须在这些结构下保持类型的不变式,否则后续推理可能丢失上下文。论文通过把变换定义为对操作语义的语义保持证明,避免了\u201c按语法对位\u201d易引入的漏洞。
六、实测数据说明了什么
论文在多个标准基准上做了对照。在过去完全无法做精确推理的高阶递归连续程序上,Slice + 离散后端首次给出了精确结果;而在已经可以精确推理的连续程序上,Slice 的结果与目前最好的精确推理系统持平。这说明它不只是\u201c在某些程序上能用\u201d,而是能扩展精确推理的覆盖面。
对工业界更现实的意义是:未来写一段带连续噪声的概率模型,可以先用 Slice 切一刀,再让现有离散引擎精确地给出后验分布,不再依赖蒙特卡洛的\u201c勉强近似\u201d——这对可靠性要求高的场景(如金融风控、控制系统、概率验证)是实打实的能力升级。
七、它意味着什么
把连续变离散,看似是把难题\u201c绕开\u201d,其实是一种很深的编程哲学:语言层的语义保持变换,可以让原本只能近似的事情变成可精确求解。它也提醒我们,类型系统不是束缚程序员的\u201c花括号税\u201d,而是程序全局结构的真实地图——很多看似只能依赖运行时统计的难题,其实答案早就在类型里写好了。
下一个十年里,概率编程大概率会和形式化方法、机器学习、量子模拟深度融合。Slice 这一类\u201c全局类型分析 + 语义保持重写\u201d的工具,会成为把概率程序从学术原型推到工程系统的关键桥梁。读这篇论文最值得带走的,不是某一个具体算法,而是这种\u201c把无穷变有限\u201d的解题思路。
