“λ 演算是函数式语言与操作语义的理论原型。替换语义直接把实参写入函数体;环境解释器则把函数表示为代码与定义环境组成的闭包。两种实现路径必须给出相同的词法绑定行为。”
形式陈述 ​
操作语义先从程序的抽象语法确定配置集合
两种常见判断形状是
前者是单步转移,完整执行由有限或无限路径组成;后者用一棵有限推导树直接证明表达式求值到结果。二者都要另行定义值、最终配置与可观察行为,箭头符号本身不会提供这些分类。
若语言有可观察错误,应使用显式 error 配置或错误判断,而不要让错误项仅仅“没有规则”。发散可由无限转移轨迹或共归纳判断
抽象机器把控制项、环境、存储与续延栈等成分显式化为机器配置。它是操作语义的一种形式,不与小步或大步判断简单同义。
语义还可以是确定的或非确定的。确定性要求
直觉
操作语义把语言规范写成一台数学解释器。规则匹配当前配置的形状,前提描述子计算,结论给出下一配置或最终结果。推导树既是行为证据,也是证明确定性、模拟和类型保持时可归纳分析的对象。
与把程序组合地映到数学对象的指称语义相比,操作语义直接保留执行结构,因此容易表达求值顺序、异常传播、状态更新与并发交错。一次语义步的粒度由规范者选择,不应未经成本对应证明就当作处理器指令。
例子与边界
以自然数和加法表达式为例,小步语义可用规则固定左到右顺序:
于是同一个表达式产生可观察的中间轨迹
大步语义不列出这些中间配置。取
直接推出
两套规则在这个终止、无错误片段上给出相同最终值,但提供的证据不同:小步轨迹记录中间项与顺序,大步推导组合子结果。若要证明二者对应,可对大步推导与小步路径分别归纳,而不能从相同算例直接推出等价。
加入赋值后,配置必须携带存储,例如 x := 1; x 的后半段无法观察前一步更新。异常若可捕获,控制栈或上下文也会影响传播位置。
必须区分三种未得到普通值的情形。true + 1 若既不是结果也没有规则,就是 stuck,可能代表非法程序或规范遗漏;若语言规定除零得到 error,则 while true do skip 或 λ 项
公理语义从另一角度用前置条件、后置条件和证明规则描述程序性质,不必列出执行步骤。操作规则可作为 Hoare 规则可靠性的参照,但两套语义承担不同职责。
推论与应用
小步语义适合观察中间状态、并发交错和非终止,大步语义适合直接组织终止求值。二者只在明确值、错误和发散条件后才有可证明的对应命题。
求值上下文可把多条上下文闭包规则压缩成“寻找唯一 redex”,环境求值则常把函数值表示为代码与定义环境组成的闭包。按需调用与代数效应处理器会分别加入堆更新或 perform/handle 转移;这些实例扩展配置和规则,却仍使用同一语义接口。
在这套接口上,进展与保持定理把类型判断与执行步骤联系起来;程序等价和编译器正确性则比较两套关系是否保持可观察行为。它们需要先固定语义,不能反过来代替动态规则。
面向程序分析时,控制流图提取可能的控制转移,收集语义在各程序点汇总操作语义可达的具体状态,抽象机器则把控制、环境和存储显式化为可执行配置。它们分别是结构投影、语义汇总和执行模型;模型检查或抽象解释算法在这些对象上工作,但语义步数仍不自动等于机器运行成本。
参考资料
- Gordon D. Plotkin, “A Structural Approach to Operational Semantics,” DAIMI FN-19, 1981; reprinted in Journal of Logic and Algebraic Programming 60–61, 2004。
- Glynn Winskel, The Formal Semantics of Programming Languages, MIT Press, 1993, Chapters 2–4。
- Benjamin C. Pierce, Types and Programming Languages, MIT Press, 2002, Chapters 3, 5, and 8。