Skip to content

模型Model

可变状态语义

施工中 · 内容逐步修订

Semantics of mutable state · Store semantics

把位置到值的存储纳入配置并随求值更新的语义。

形式陈述 ​

操作语义把存储 σ 纳入状态机的运行配置。设位置集合为 Loc、值集合为 Val,则存储是有限部分函数 σ:Loc⇀Val。表达式求值写作 ⟨e,σ⟩→⟨e′,σ′⟩;分配产生新鲜位置,读取查询 σ(ℓ),赋值把存储更新为 σ[ℓ↦v]。

变量环境与存储必须分开:前者把源语言变量映到值或位置,后者把位置映到当前内容。是否可观察位置身份、何时回收不可达位置,以及分配失败如何处理,都属于具体语言语义的一部分。

若还要证明类型安全,静态语义通常加入存储类型 Σ,记录每个已分配位置可保存的值类型,并维持 Σ⊢σ;分配可用新位置扩展 Σ,而读取和写入必须与对应位置的类型一致。

直觉

纯 λ 演算中,变量可由值替换;一旦引入可变引用,同一个位置的内容会随时间改变,程序含义便依赖“现在的存储是什么”。最有效的图像是两层映射:变量名找到一个抽屉编号,存储记录每个抽屉此刻装什么。别名使两个不同表达式指向同一抽屉,因此局部赋值可能被远处代码观察到。闭包捕获可变变量时也通常保存这个位置,而非复制某一时刻的内容。

例子与边界

程序 let r = ref 0 in r := 1; !r 先分配新位置 ℓ 并存入 0,赋值把存储更新为 σ[ℓ↦1],最后读取结果 1。若再令 s = r,则 s := 2 后 !r 也为 2,因为 r 与 s 是同一位置的别名。

边界是把赋值误作普通代换。表达式 f(r); !r 的结果取决于 f 是否能写入该位置,不能把 r 在源码中简单替换为初始值。垃圾回收通常不改变可观察语义,但若语言暴露地址、终结器或弱引用,就需要更细致的等价条件。

推论与应用

可变状态语义为命令式语言、对象、数组和函数共享可变位置提供基础。分离逻辑以堆的可分资源结构支持局部推理,所有权与借用则用静态 owner、loan 和生命周期限制别名访问;两者都建立在位置与存储之上,却不是运行配置本身。

静态分析可把许多具体位置归入有限抽象单元。Andersen分析从取地址、复制和间接读写生成包含约束;Steensgaard分析则用存储形状合一压缩目标表示。二者都要覆盖真实别名,但合一可能把只经一个汇合变量相遇的两个目标传播回其他变量,精度差别可在四条赋值上手算出来。

面向对象程序还可用对象敏感分析,按接收者的抽象身份区分同一方法的调用上下文。这与按字段名区分存储槽是两项选择;若两个真实对象已被合并到同一抽象堆名,方法上下文也无法凭空恢复它们的区别。

在并发环境中,多个线程共享 σ 会产生数据竞争和原子性问题;事务、内存模型与并发对象语义都可看作对这套基本配置的扩展。证明有状态程序等价或表示独立时,有状态逻辑关系还需用 possible worlds 或 step index 记录两边堆单元的持续对应,而不能只比较当前返回值。

参考资料
  • Robert Harper, Practical Foundations for Programming Languages, 2nd ed., Cambridge University Press, 2016,Chs. 34–36, state, references, and store typing。
  • Glynn Winskel, The Formal Semantics of Programming Languages, MIT Press, 1993,Chs. 2–5, transition semantics with stores。
关系图谱34 个相邻概念 · 1 类关系

拖动节点调整位置。

显示关系

显示:依赖

  1. 前置三跳
  2. 前置二跳
  3. 前置一跳
  4. 当前条目
  5. 后续一跳
  6. 后续二跳
  7. 后续三跳
文字版关系按与当前条目的最短距离分组