“由二者归纳可得:良类型闭项的任意有限求值前缀都不会到达一个既非值又无后继的卡住项。有存储、异常或并发时,需要把判断扩展到配置,并加入存储良类型、允许的最终结果等不变量。效应系统还要让运行时实…”
形式陈述 ​
效应系统把普通类型判断扩展为
表示
在一个基础的集合效应系统中,值本身可有空效应;函数类型记录调用时才发生的潜在效应:
应用与顺序组合累积各子计算及函数体的效应:
若
可靠性的典型形式是:若闭项
直觉 ​
结果类型回答“计算完成后交出什么”,效应标注回答“为得到结果,计算可能触碰什么”。一个返回整数的函数可能只做纯算术,也可能读文件、写数据库或抛异常;仅看 Int 无法区分这些行为。效应系统把这种差别留在静态接口中,使调用者能在不运行程序时作保守判断。
潜在效应与立即效应必须分开。创建一个函数值只封装函数体,通常不执行其中的 I/O;所以 λ 表达式自身可纯,而它的箭头类型记住将来调用时的 io。若漏掉这一层,系统要么错误地把所有函数创建都算成执行效果,要么在真正调用时丢失效果。
例子与边界 ​
设
表达式 fun p -> load p 在创建闭包时没有读文件,因而外层判断可带 load configPath 时,参数求值、函数求值与潜在效应合并,结果判断覆盖 I/O 和异常。若程序先检查缓存并只在未命中时读取文件,静态标注仍可能含 io,即使某次运行没有发生读取。
空效应也只有在系统的可靠性前提成立时才能支持“不会发生所跟踪效应”的结论。不安全外部函数若被错误声明为纯,或语义中存在未纳入效应代数的隐蔽通道,都会破坏推论。效应系统通常也不决定求值顺序:集合
效应系统与代数效应处理器位于不同层面。前者静态近似程序可能触发哪些操作;后者在运行语义中规定 perform 如何被 handler 接住和恢复。语言可以同时拥有二者,也可以只拥有其中一个。
推论与应用 ​
效应标注可用于验证纯函数边界、限制异常传播、指导并行化,以及判断表达式移动或重排是否可能改变可观察行为。区域效应还能指出计算读写哪些存储区域,为别名分析和安全优化提供依据。
多态效应或 row polymorphism 允许库函数保留调用者传入函数的未知效应,而不是把它粗略放大为“任意效果”。这是基础效应判断的扩展;只有当固定效应集合造成真实复用问题时,才需要引入行变量和相应约束求解。
参考资料
- John M. Lucassen and David K. Gifford, “Polymorphic Effect Systems,” POPL, 1988。
- Jean-Pierre Talpin and Pierre Jouvelot, “The Type and Effect Discipline,” Information and Computation 111(2), 1994。
- Daan Leijen, “Koka: Programming with Row Polymorphic Effect Types,” EPTCS 153, 2014。