名称: 指称语义构建器 描述: ‘构建指称语义模型。适用于:(1) 形式化语言语义,(2) 证明程序属性,(3) 语义分析。’ 版本: 1.0.0 标签:
- 语义学
- 指称语义
- 域理论
- 编程语言基础 难度: 高级 语言:
- Haskell
- Coq 依赖:
- 操作语义定义器
指称语义构建器
为编程语言构建指称语义模型。
何时使用
- 形式化语义定义
- 证明程序属性
- 语义等价性
- 语言设计
本技能的功能
- 定义域 - 语义域
- 映射语法 - ⟦e⟧ : Exp → D
- 组合性 - 从部分构建意义
- 处理递归 - 不动点语义
核心理论
指称语义:
⟦e⟧ ∈ D 其中D是语义域
⟦n⟧ = ⟦n⟧ℤ ∈ ℤ
⟦x⟧ = ρ(x) ∈ D
⟦λx.e⟧ = λd. ⟦e⟧(ρ[x↦d])
⟦e₁ e₂⟧ = ⟦e₁⟧(⟦e₂⟧)
实现
from typing import Dict, Callable, Generic, TypeVar, Set
from dataclasses import dataclass
# 语义域
Domain = TypeVar('Domain')
Value = TypeVar('Value')
# 基本域
class Int:
"""整数"""
def __init__(self, n: int):
self.n = n
class Bool:
"""布尔值"""
def __init__(self, b: bool):
self.b = b
# 函数域
class Fun(Generic[Domain, Value]):
"""函数域 D → E"""
def __init__(self, f: Callable[[Domain], Value]):
self.f = f
def apply(self, x: Domain) -> Value:
return self.f(x)
# 乘积域
class Prod(Generic[Domain, Value]):
"""乘积域 D × E"""
def __init__(self, first: Domain, second: Value):
self.first = first
self.second = second
# 环境
class Env(Dict[str, Value]):
"""运行时环境"""
pass
# 指称语义
class DenotationalSemantics:
"""简单语言的指称语义"""
def __init__(self):
self.functions = {}
def sem_int(self, n: int) -> Int:
"""⟦n⟧ = n"""
return Int(n)
def sem_bool(self, b: bool) -> Bool:
"""⟦b⟧ = b"""
return Bool(b)
def sem_var(self, x: str, env: Env) -> Value:
"""⟦x⟧ = ρ(x)"""
return env[x]
def sem_lambda(self, x: str, body: 'Expr', env: Env) -> Value:
"""⟦λx.e⟧ = λd. ⟦e⟧(ρ[x↦d])"""
def semantics(d: Value) -> Value:
new_env = Env(env)
new_env[x] = d
return self.sem(body, new_env)
return Fun(semantics)
def sem_app(self, e1: 'Expr', e2: 'Expr', env: Env) -> Value:
"""⟦e₁ e₂⟧ = ⟦e₁⟧(⟦e₂⟧)"""
v1 = self.sem(e1, env)
v2 = self.sem(e2, env)
return v1.apply(v2)
def sem_if(self, cond: 'Expr', then: 'Expr', else_: 'Expr', env: Env) -> Value:
"""⟦if e then e₁ else e₂⟧"""
v = self.sem(cond, env)
if v.b:
return self.sem(then, env)
else:
return self.sem(else_, env)
def sem(self, expr: 'Expr', env: Env) -> Value:
"""主要语义函数"""
match expr:
case Int(n):
return self.sem_int(n)
case Bool(b):
return self.sem_bool(b)
case Var(x):
return self.sem_var(x, env)
case Lambda(x, body):
return self.sem_lambda(x, body, env)
case App(e1, e2):
return self.sem_app(e1, e2, env)
case If(cond, then, else_):
return self.sem_if(cond, then, else_, env)
不动点语义
class RecursiveSemantics:
"""带递归的语义,使用不动点"""
def __init__(self):
self.functions = {}
def fix(self, F: Callable[['Value'], 'Value']) -> 'Value':
"""不动点计算(Kleene迭代)"""
# 从底部开始迭代
x = None
while True:
fx = F(x)
if fx == x:
return x
x = fx
def sem_letrec(self, x: str, e1: 'Expr', e2: 'Expr', env: Env) -> Value:
"""⟦letrec x = e₁ in e₂⟧"""
# 创建递归环境
def F(f):
new_env = Env(env)
new_env[x] = f
return self.sem(e2, new_env)
# 计算不动点
# 这为递归定义提供意义
return self.fix(F)
def sem_while(self, cond: 'Expr', body: 'Expr', env: Env) -> Value:
"""⟦while e do c⟧"""
while True:
v = self.sem(cond, env)
if not v.b:
return Bool(True)
self.sem(body, env)
域理论
class Domain:
"""完全偏序"""
def __init__(self):
self.elements = set()
self.partial_order = {}
def lub(self, chain: Set['Value']) -> 'Value':
"""链的最小上界"""
# 在完全偏序中:链的lub存在
pass
def bot(self) -> 'Value':
"""底部元素(⊥)"""
pass
def le(self, x: 'Value', y: 'Value') -> bool:
"""偏序(⊑)"""
pass
# 提升域
class Lifted(Generic[Domain]):
"""带底部的域"""
def __init__(self, d: Domain, bottom: Value):
self.domain = d
self.bottom = bottom
# 严格函数
class StrictFun(Domain):
"""严格函数(⊥ → ⊥ = ⊥)"""
def __init__(self, dom: Domain, cod: Domain):
self.domain = dom
self.codomain = cod
def apply(self, x: Value) -> Value:
if x == self.domain.bottom:
return self.codomain.bottom
# 应用函数
pass
等价性证明
class SemanticEquivalence:
"""证明语义等价性"""
def prove_eq(self, e1: 'Expr', e2: 'Expr') -> bool:
"""证明 ⟦e₁⟧ = ⟦e₂⟧"""
# 计算指称
d1 = self.sem(e1, {})
d2 = self.sem(e2, {})
return d1 == d2
def prove_extensional(self, e1: 'Expr', e2: 'Expr') -> bool:
"""
外延等价性:
∀ρ. ⟦e₁⟧ρ = ⟦e₂⟧ρ
"""
# 测试各种环境
test_envs = self.generate_test_envs()
for env in test_envs:
d1 = self.sem(e1, env)
d2 = self.sem(e2, env)
if d1 != d2:
return False
return True
指称语义 vs 操作语义
操作语义: 程序如何执行(步骤)
⟦e⟧ → v (逐步执行)
指称语义: 程序的意义(数学)
⟦e⟧ ∈ D (直接映射)
关系:
操作语义 → 指称语义(适当性)
指称语义 → 操作语义(完全抽象)
关键概念
| 概念 | 描述 |
|---|---|
| 语义域 | 数学结构 |
| 组合性 | 从部分构建意义 |
| 不动点 | 递归语义 |
| 适当性 | 操作语义 ↔ 指称语义 |
| 完全抽象 | 上下文等价性 |
经典参考文献
| 参考文献 | 重要性 |
|---|---|
| Stoy, “Denotational Semantics: The Scott-Strachey Approach to Programming Language Theory” (1977) | 指称语义的权威教科书 |
| Winskel, “The Formal Semantics of Programming Languages” (1993) | 全面处理 |
| Abramsky & Jung, “Domain Theory” (1994) | 数学基础 |
| Gordon, “The Denotational Description of Programming Languages: An Introduction” (1979) | 入门教科书 |
提示
- 从简单类型开始
- 使用域理论处理递归
- 后证明适当性
- 考虑外延性
相关技能
operational-semantics-definer- 操作语义hoare-logic-verifier- 公理语义lambda-calculus-interpreter- λ演算
研究工具与成果
域理论和指称语义工具:
| 资源 | 学习内容 |
|---|---|
| Stoy的"Denotational Semantics" | 基础文本 |
| Winskel的"Formal Semantics" | 程序员的域理论 |
| Gunter, “Semantics of Programming Languages: Structures and Techniques” (1992) | 包含域理论的全面覆盖 |
| MLton | 全程序编译器带语义分析 |
证明助手形式化
- Coq标准库 - 范畴理论、域理论
- Iris - 高阶分离逻辑
- 笛卡尔闭范畴 - 编程的范畴理论
研究前沿
1. 博弈语义
- 方法: 程序作为博弈中的策略
- 优势: 精确捕获顺序行为
- 论文: “Full Abstraction for PCF” (Abramsky, Jagadeesan, Malacaria 2000; Hyland, Ong 2000)
- 应用: PCF的完全抽象、验证
2. 关系语义
- 方法: 程序间的关系
- 优势: 证明关系属性
- 论文: “Simple Relational Correctness Proofs for Static Analyses and Program Transformations” (Benton, 2004)
- 应用: 程序等价性、编译器正确性
3. 度量语义
- 方法: 程序作为度量空间中的点
- 优势: 定量推理
- 论文: “Metric Semantics” (de Bakker, America)
- 应用: 概率程序、双模拟
4. 步进索引语义
- 方法: 分层语义定义
- 优势: 处理递归和步进计数
- 论文: “An Indexed Model of Recursive Types” (Appel & McAllester, 2001)
- 应用: 基础证明携带代码、分离逻辑
实现陷阱
| 陷阱 | 实际后果 | 解决方案 |
|---|---|---|
| 缺少底部元素 | 未表示非终止性 | 所有域添加⊥ |
| 非连续函数 | 不动点可能不存在 | 确保单调性 |
| 错误的域提升 | 严格性问题 | 使用严格函数空间 |
| 不适当的适当性 | 语义不匹配行为 | 证明适当性定理 |
“不动点需要连续性”问题
并非所有不动点计算正确:
# 错误: 非单调函数
def F(f):
if f(0) > 0: return lambda x. 0
else: return lambda x. 1
# 正确: 单调函数(针对指称语义)
# f是单调的: 如果 a ⊑ b 则 F(a) ⊑ F(b)
# 然后Kleene不动点收敛
“适当性差距”
操作语义和指称语义必须匹配:
指称语义: ⟦e⟧ = ⊥ (不终止)
操作语义: e →* ⊥ (发散)
适当性: 如果 ⟦e⟧ = v 则 e →* v
如果 ⟦e⟧ = ⊥ 则 e 发散(或卡住)