伴随求值

伴随求值是一种类型论, 它将类型分为两类:

值类型, 当我们描述它们的实例时, 我们描述它们的构造本身, 换言之它以构造规则为主, 极性为正,

计算类型, 当我们描述它们的实例时, 我们描述对于来自外部的输入, 它们如何响应. 换言之这些类型以消去规则为主, 极性为负.

借助这种分层, 计算单子可以被解构成一对伴随.

类似伴随逻辑把命题分为两类, 并且给出一对互相转换的逻辑连接词, 伴随求值也给出了互相转换的连接词. 但与之不同的是, 伴随求值在语法上就区分计算类型和值类型, 并且一般只考虑两类类型.

伴随求值的表达式也随着类型被分类, 但表达式比起类型还多了一种: . 这意味着伴随求值中有三类不同的判断.

1语法

由于伴随求值的框架非常可扩展, 全面地考虑所有可能的类型并不现实, 这里只考虑单位类型积类型无交并类型函数类型这几个基本的类型构造. 值类型和计算类型的语法使用形式语言定义如下:

其中, 类似积类型, 类似无交并类型, 类似函数类型, 剩下 类似伴随逻辑中的 , 类似 .

非常类似线性逻辑中的 , 前者是值, 换言之它的实例是两个值放在一起; 后者是计算, 它的实例包含两个计算, 对它来说外部输入就是对这两个计算中的一个进行一次选择, 然后它的响应方式就是执行该选择.

伴随求值中最核心的类型就是 了. 对于计算 , 表示类型为 的计算的代码, 这个代码可以像值一样被传递、被放进其它的值进行组合, 也可以被恢复成计算并执行. 对于值 , 表示最终会给出类型为 的结果的一段计算.

表达式的语法定义如下:

其中 的规则, 的规则.

2类型规则

针对计算和值, 分别有两类判断来处理它们:

计算的判断 ,

值的判断 .

其中, 语境 是一组值类型. 这至关重要, 因为语境决定了变量的类型和替换操作里面能传入什么样的数据. 既然语境里面都是值类型, 那么变量的类型都是值类型.

针对值类型, 有如下规则:

针对计算类型, 有如下规则:

3语义

除了表达式的类型规则, 为了描述语义, 需要引入栈的概念, 及其对应的判断, 如下所示:

它有前提条件 必须成立. 栈表示 “接下来需要进行的计算”. 这个判断的意思是在语境 中, 我们拿着 , 在执行完 后还要把它的结果传递给 完成接下来的计算, 最后给出的结果类型为 .

根据 的不同, 对栈的操作有两种可能:

入栈: 将 的一部分拆下来放进 ,

出栈: 把 顶部的数据取出并和 结合.

操作语义

范畴语义

范畴论中解释伴随求值需要分别解释值类型和计算类型. 其中值类型的解释非常类似 Curry–Howard–Lambek 对应中对简单类型 演算的解释, 接下来我们把这个范畴记作 .

需要注意的是, 简单类型 演算对应积闭范畴再加上余积, 但对于前文介绍的伴随求值来说这会多出来一些构造, 比如语法里没有值到值的函数, 因此没有指数对象的直接对应物, 但给伴随求值加上这个类型很容易, 所以这种事情可以忽略.

计算类型的解释则相对复杂一些. 我们不直接解释计算类型的实例 , 而是解释. 考虑栈的判断 , 由于栈处理一个计算 , 可以把 的类型 视为栈的输入、 视为其输出, 那么这可以看作一个计算类型 之间的态射. 注意这里还有值类型构成的语境 , 因此计算类型的范畴和值类型的范畴构成范畴族, 其中值类型的范畴是指标. 具体来说, 计算类型的范畴是局部 -范畴族, 定义如下.

定义 3.1. 局部 -范畴族-函子 (换言之这是严格的范畴族), 满足如下条件:

对于 , 它诱导的函子 在对象上是恒同映射.

局部 -范畴族是一种严格的局部常纤维范畴.

由于伴随求值中替换操作不改变类型, 因此我们要求对应替换操作的函子在对象上恒同, 但它不一定在态射上恒同, 这是因为替换操作可能会改变栈. 计算类型的范畴中, 恒同态射对应空的栈, 态射复合对应栈的拼接.

4参考文献

Paul Blain Levy (2001). “Call-By-Push-Value”. (web)

Robert Harper (2024). “Call-By-Push-Value and the Enriched Effect Calculus”. (web)

术语翻译

伴随求值英文 call-by-push-value

英文 stack

入栈英文 push

出栈英文 pop