# 作用与余作用 ## 作用 (Effects) Effects 是程序中对系统状态或外部环境产生影响的操作:I/O、状态修改、资源占用等。 学术界对作用有两种主要建模方式: ### 单子作用 (Monadic Effects) - 通过单子 (monad) 将副作用封装为类型安全的计算链。 - 提供 `return`(纯值注入)和 `bind`(链式组合)两个基本操作。 - 以纯函数式的方式处理带有副作用的计算。(Moggi 1991, Wadler 1992) - 代表语言:Haskell (IO Monad)、Rust (Result/Option) ### 代数作用 (Algebraic Effects) - 允许在函数中"抛出"一个 effect,在调用栈的更高层次"捕获"并处理。 - 类似异常处理,但更通用——处理后可以恢复执行。 - 代表语言:Koka、Eff、OCaml 5+ (Kiselyov 2018, Kawahara 2020) ## 余作用 (Coeffects) Coeffects 是程序执行时依赖的上下文信息:环境变量、系统资源、外部服务等。 - Coeffects 是 effects 的对偶 (dual) 概念,通常通过余单子 (comonad) 建模。(Petricek 2013, 2014; Brünnler 2014) - 更前沿的理论将带有资源的上下文建模为 **graded algebra**(有序半环加最大元): - 加法 = 并行组合;0 元 = 无资源 - 乘法 = 串行组合;1 元 = 单位资源 - 序 = 资源约束;最大元 = 无限资源 - (Breuvart 2015, Gaboardi 2016, Dal Lago 2022) ## 现有理论的不足 这些理论主要面向**静态分析**和**短时程序**: 1. **缺乏运行时追踪**:类型系统能标记副作用的存在,但无法在运行时追踪和回收。对长时运行程序(服务端、Agent),这意味着资源泄漏不可避免。 2. **缺乏动态性**:面向编译期分析,无法处理运行时的加载/卸载需求。 3. **崩溃而非降级**:类型不满足时直接拒绝编译或运行时崩溃,而长时运行程序更希望安全降级——挂起不满足依赖的部分,而非停止整个系统。 ## Cordis 的突破 Cordis 选择了不同的路径——在运行时层面解决可组合性问题: | 现有理论 | Cordis 方案 | |----------|-------------| | 类型标记副作用 | 运行时追踪并自动回收副作用 | | 编译期拒绝 | 运行时挂起/恢复 | | 面向短时程序 | 面向长时运行程序设计 | 这由两个互补机制实现: - **[可逆作用](revertible-effects)** — 将副作用形式化为可逆的群操作 - **[响应式余作用](reactive-coeffects)** — 将依赖建模为具有生命周期的服务 ## 在 Agent 开发中的意义 对 DeepSeek Harness 而言,作用/余作用模型直接支撑了以下能力: | 作用 (Effect) | 余作用 (Coeffect) | |---------------|-------------------| | 注册一个 tool | 依赖 tool registry 服务 | | 注册一个 LLM adapter | 依赖 LLM 服务接口 | | 监听 session 事件 | 依赖 session 服务存在 | | 启动子进程 | 依赖 bash executor 实现 | 每一个 effect 都可逆(tool 可注销、adapter 可移除);每一个 coeffect 都有生命周期(服务消失则依赖者挂起)。这就是 Agent 能被安全热替换的根本原因。