Continuation-Passing Style
(简写为CPS)是一种代码控制流的实现方式。内容部分来自这里。
Continuation
Continuation
是指在一个逻辑算法或者功能中,某一计算时刻,之后的所有计算逻辑。
例如
static void M()
{
var x = 5;
F(); // <----------- Point in the computation
++x;
Console.WriteLine(x);
}
static void Main()
{
M();
Console.WriteLine("Done");
}
那么在调用F
时的Continuation,就是++x
和Console.WriteLine(x)
。
将Continuation
封装为函数的一个参数,当函数执行完时,不是返回,而是通过调用传入的Continuation
传递计算结果,继续往下执行,这种方式就是CPS。
CPS改造
比如取最大值函数
static int Max(int n, int m)
{
if (n > m)
return n;
else
return m;
}
转为CPS需要这几步:
- 修改返回值类型为
void
- 添加一个额外的Continuation参数
Action<T>
, 其中T是函数原本的返回类型。 - 用新添加的Continuation参数替换原函数中所有的
return
语句,传入的参数是原返回值
static void Max(int n, int m, Action<int> k)
{
if (n > m)
k(n);
else
k(m);
}
于是原本调用方式也从:
static void Main()
{
Console.WriteLine(Max(3, 4));
}
变为:
static void Main()
{
Max(3, 4, x => Console.WriteLine(x));
}
其他
CPS可以是函数更灵活的控制执行流程,实现不同的控制流。c#中的异步(async/await
)就使用了CPS实现(以及状态机)。
除此之外,CPS可以可以节省栈内存,因为函数的执行不需要记录返回值,返回值直接通过传入的Continuation
进行下一步处理了。
但是CPS写的代码不如普通的控制流容易理解,一遍可能编译器的书写者比较熟悉他的含义。