“固定有限的带标签程序,并先把不同绑定器的变量唯一命名,避免同名遮蔽被误当成同一绑定。为说明经典构造,可先转成续延传递风格:返回也表现为调用一个续延闭包,不再有隐含机器栈。整数等非函数值在本分…”
形式陈述
固定一个以λ 演算为核心的左到右传值调用源语言,以及答案类型
类型翻译可取基础类型
若源项有
对闭合、纯、确定的源语言,一种语义保持陈述是:若
直觉
直接风格函数“返回”结果,CPS 函数则收到一份结果去向,并在完成时调用它。原本藏在宿主调用栈中的“接下来做什么”变成普通函数参数。每个中间结果都立刻交给下一段控制,因此翻译后的核心项可整理成尾调用形式。
CPS 是系统变换,不只是把某个回调手写出来。语法的每一种构造都必须有条款,条款共同保存源语言的求值顺序、作用域与控制效果。翻译后出现的 λf、λv 以及“立即构造再立即调用”的小函数,是变换制造的行政结构,不代表源程序新增业务计算。
例子与边界
令 square 3 + 1,把加法也按左到右翻译,有
中间的 λw.k(u+w) 接到常量 k(u+1);消除这类 administrative redex 可缩短目标程序,但必须保持绑定和求值顺序。
异常可翻译成同时接收成功续延与失败续延的双续延程序,抛出时调用失败续延。这只是特定源语言的一种 CPS 实例。带状态、受限控制、调用名或不同答案类型的语言会产生不同翻译;不存在一套脱离源/目标语义仍“完全保序”的唯一公式。
推论与应用
CPS 使异常、非局部跳转和一等控制成为显式函数调用,也常用作编译器中间表示。对有限种续延函数做 defunctionalization,可把它们变成抽象机器的帧;这解释了显式控制栈如何由高阶求值器导出。
去函数化从有限函数抽象位置产生构造子和apply分派,普通Add/Mul/Compose函数族也适用。trampoline则把用户函数和续延的尾调用都延迟成返回任务,由while逐个执行;n=3求和的一阶任务机走8步,宿主调用深度有界而堆续延仍有3帧。
正确的编译器证明还需区分类型保持、终止结果保持、发散反射与上下文等价等目标。单看生成项“能运行”不足以证明变换正确;行政归约和优化也必须在已声明的源—目标观察关系下验证。
行政正规形(ANF)也显式安排左到右求值,但目标函数仍普通返回,中间结果由 let 命名,并未把续延作为目标程序参数。其编译算法用一个高阶函数组织输出,不构成输出已经是 CPS 的证明;两种变换的相邻接口应按各自目标文法核对。
参考资料
- Gordon D. Plotkin, “Call-by-Name, Call-by-Value and the λ-Calculus,” Theoretical Computer Science 1, 1975。
- Olivier Danvy and Andrzej Filinski, “Representing Control: A Study of the CPS Transformation,” Mathematical Structures in Computer Science 2(4), 1992。
- Andrew W. Appel, Compiling with Continuations, Cambridge University Press, 1992。