Reactive Coeffects (反应式上涵)
在 Spatiotemporal Composability (时空可组合性 范式中,组件声明它对环境的需求 (coeffect specification);每当 context 变化(依赖出现、消失、改换身份),runtime 把变化通知给声明该依赖的组件,并按 activating / deactivating / neutral 三态分类。Shi, Zhang & Cui (2026) Section 3.2 的核心构造。
形式化定义
Coeffect Context
\Sigma = K \xrightarrow{\mathrm{fin}} V_k 键 K 到值类型 V_k 的有限偏函数——coeffect 表的并,即当前所有 active fiber 安装的依赖集合。Component 持有: - specification d \subseteq K:声明的依赖键。 - provision p \subseteq K:可提供的键。 ### Specification 与 Notification Definition 24 对每个 k,附带一组操作 \mathcal{A}_k(含 forward map + yielded inverse)。值 v \in V_k 配等价关系 \simeq_k("观测等价"),由操作确定。 Definition 25 组件声明 specification d : \mathcal{D}_\Sigma,是 key 的多集(带 allow-optional 标记)。 Definition 26 通知——给定旧/新 coeffect 状态 \sigma, \sigma',对每个声明的 key k \in d,判定: - activating:\sigma \not\models d 且 \sigma' \models d(新依赖就绪) - deactivating:\sigma \models d 且 \sigma' \not\models d(依赖消失) - neutral:其余(依赖提供方变了但仍满足) ### Satisfaction Predicate \sigma \models d \;:\Longleftrightarrow\; \forall k \in d.\, k \in \mathrm{dom}(\sigma)
Isolation 与 Interception
- Isolation(Definition 28):每个 fiber 的 context 可声明
isolate: { key: realm }映射——同一 key 在不同 realm 由不同 fiber 提供,互不干扰。 - Interception(Definition 30):coeffect 携带 metadata,consumer 调用时 provider 查 metadata 决定请求是否允许(capability-based 访问控制)。
与 classical coeffect 体系的关系
| Classical coeffect (Petricek, Uustalu-Vene) | Reactive coeffect | |
|---|---|---|
| 描述 | 类型 / 类型上下文标注 | 运行时 specification + 通知 |
| 推理时机 | 编译期 | 运行时 |
| 依赖变化 | 编译期 fixed | 三态通知(activating / deactivating / neutral) |
| 隔离 | 词法作用域 | Realm table(runtime override) |
| 拦截 | 编译期类型检查 | Provider 查 context metadata |
运行时三态
- activating:dependency 出现 → 组件从 Inactive 转 Reloading → Active。
- deactivating:dependency 消失 → 组件转 Unloading → 等
relied_n(γ)守卫释放 → L-Unload(累加器撤销 effect)→ Inactive。 - neutral:provider 换了但语义等价(idempotent set 注册)→ 不触发 reload。
relied_n(γ)(Definition 50):\exists m, k.\, m \neq n \wedge \mathrm{installed}_m(\gamma) \wedge \omega_m(k) = n——n 还有别的已安装 fiber 仍把它当 provider,则 n 不能立即撤销。
在 Cordis 中的实现
class MyConsumer extends Context {
// 声明依赖
inject = ['db', 'logger']
constructor(ctx: Context) {
super(ctx, 'my-consumer')
// ctx['db'] 走 Algorithm 6:沿 fiber 链向上 walk 找 committed view
// 命中 → 返回;inject 但未 commit → INACTIVE_ACCESS
// 走到 root 仍未声明 → UNDECLARED_ACCESS
}
}
Algorithm 6 Proxy 解析——resolve(ctx, key):
- 当前 fiber 命中 committed view → 返回。
- 命中 inject 但未 commit → 抛
INACTIVE_ACCESS。 - 走到 root 仍无声明 → 抛
UNDECLARED_ACCESS。 - 否则向 parent.fiber 走一步。
案例:Koishi 切换数据库 backend
Koishi 切换数据库后端时:所有声明 inject = ['db'] 的 plugin 自动重新激活;未声明 db 的 plugin 保持不变。plugin 作者之间不需协调——只需对 coeffect key 名字达成一致。
与 quant 系统的潜在接口
- 因子 / datafeed 切换:把数据源声明为 coeffect key,切换时只有声明该 key 的策略重激活。
- 风险模型版本切换:将 risk-model 版本作为 realm,调用方透明切换。
- Agent-trading 工具依赖:模型生成的 tool 之间用 coeffect key 协调,无需中心编排器。
详见 Spatiotemporal Composability (时空可组合性 页中标注的迁移接口。