延续只是将“接下来发生的事情”视为第一类对象,可以无条件使用一次,忽略以支持其他内容,或多次使用。
为了说明Continuation Passing Style是什么,下面是一些正常写的表达式:
let h x = f (g x)
g 应用于x,f 应用于结果。
请注意,g 没有任何控制权。无论如何,它的结果都会传递给 f。
在 CPS 中是这样写的
let h x next = (g x (fun result -> f result next))
g 不仅有 x 作为参数,还有一个延续 g 的输出并返回最终值。该函数以同样的方式调用f,并将next作为延续。
发生了什么?是什么改变使它比f (g x) 更有用?不同之处在于现在g 处于控制之中。它可以决定是否使用接下来发生的事情。这就是延续的本质。
出现延续的一个例子是具有控制结构的命令式编程语言。 While、block、普通语句、break 和 continue 都是通过 continuation 泛化的,因为这些控制结构接受接下来发生的事情并决定如何处理它,例如我们可以有
...
while(condition1) {
statement1;
if(condition2) break;
statement2;
if(condition3) continue;
statement3;
}
return statement3;
...
while、block、statement、break 和 continue 都可以在函数模型中通过 continuation 来描述。每个构造都可以被认为是一个接受
- 当前环境包含
- 封闭范围
- 可选函数接受当前环境并返回一个继续
- 从最里面的循环中断
- 从最里面的循环继续
- 从当前函数返回。
- 与其关联的所有块(if-blocks、while-block 等)
- 下一条语句的继续
并返回新环境。
在while循环中,根据当前环境对条件进行求值。如果它被评估为真,那么块被评估并返回新环境。返回使用新环境再次评估 while 循环的结果。如果它被评估为假,则返回评估下一条语句的结果。
使用 break 语句,我们在环境中查找 break 函数。如果没有找到函数,那么我们不在循环中,我们给出一个错误。否则,我们将当前环境赋予函数并返回评估的延续,这将是 while 循环之后的语句。
使用 continue 语句会发生同样的情况,除了继续是 while 循环。
使用 return 语句,延续将是调用当前函数之后的语句,但它会从环境中删除当前的封闭范围。