Language agnostic 理解无限延续
假设我有以下代码(类似C的语法): void foo(int arg){…} 整型条(){ ... //连续呼叫 ... } foo(bar()) //foo调用之后 1) 函数Language agnostic 理解无限延续,language-agnostic,programming-languages,functional-programming,continuations,Language Agnostic,Programming Languages,Functional Programming,Continuations,假设我有以下代码(类似C的语法): void foo(int arg){…} 整型条(){ ... //连续呼叫 ... } foo(bar()) //foo调用之后 1) 函数foo调用函数bar,该函数一直运行,直到它通过调用continuation到达行 2) 在这一行创建了一个continuation函数。它表示条和foo的其余部分。continuation函数作为参数传递给调用continuation函数 3) 带continuation的调用函数对参数执行任何操作(例如,它可能只存储
foo
调用函数bar
,该函数一直运行,直到它通过调用continuation
到达行
2) 在这一行创建了一个continuation
函数。它表示条
和foo
的其余部分。continuation
函数作为参数传递给调用continuation
函数
3) 带continuation的调用
函数对参数执行任何操作(例如,它可能只存储在全局变量中)并返回
4) 一旦带有continuation的调用返回,我们立即跳转到带有“after foo invocation”的行,其余的条
和foo
不会执行
5) 为了继续执行bar
和foo
,我们应该显式调用continuation
函数(在(2)中创建,可能存储在(3)中)。调用continuation
函数后,执行将在使用continuation调用后立即继续
对吗?我是否遗漏了一些关于无限制延续的内容?否。通常,无限制延续(例如使用Scheme的调用/cc
创建)在调用延续时跳转,而不是在调用调用/cc
时跳转(也称为使用当前延续调用)
因此,请充实您的示例:
continuation savedk;
void foo(int arg) { ... }
int bar() {
...
call/cc(handler)
// after call/cc
println "after call/cc"
...
}
void handler(continuation k) {
savedk = k
}
foo ( bar() )
// after foo invocation
执行开始。我们输入bar
(我们还没有输入foo
;我们将在完成bar
后再输入)
当我们在bar
中点击对call/cc
的调用时,“程序上下文”变成了一个称为continuation的对象。此时,程序上下文包括“完成执行bar
,然后对结果调用foo
,然后执行foo
调用之后的任何操作”。将继续传递给函数,该函数作为call/cc
的参数,在上面的示例中是handler
处理程序
对延续执行某些操作。假设它存储在一个全局变量中。然后它返回到调用/cc
调用之后的点,仍然在栏中
假设我们在这一点上打印出一些东西。然后bar
结束,我们称之为foo
,它就结束了
如果我们现在在savedk
中应用continuation,控件将跳回bar
,并将程序上下文恢复为“完成执行bar
,然后对结果调用foo
,然后执行foo
调用之后的任何操作”。所以我们又印了一行。事实上,如果我们不清除savedk
变量或测试其他一些状态,如果再次调用savedk
“执行foo
调用之后的任何操作”,我们可能会得到一个无限循环
您描述的行为(步骤4-bar和foo的其余部分不执行)只有在您可以选择要跳过执行的点时才有意义。这将使它成为分隔的延续。但是,在诸如reset
/shift
等常用分隔的延续API中,调用延续的行为类似于函数调用,而不是跳转,因为在这种延续完成后,它会返回调用它的代码。
continuation savedk;
void foo(int arg) { ... }
int bar() {
...
call/cc(handler)
// after call/cc
println "after call/cc"
...
}
void handler(continuation k) {
savedk = k
}
foo ( bar() )
// after foo invocation