Language agnostic 理解无限延续

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的调用函数对参数执行任何操作(例如,它可能只存储

假设我有以下代码(类似C的语法):

void foo(int arg){…} 整型条(){ ... //连续呼叫 ... } foo(bar()) //foo调用之后 1) 函数
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