如何理解这种延续?

时间:2012-07-01 16:05:12

标签: scheme the-little-schemer

(let ([x (call/cc (lambda (k) k))])
    (x (lambda (ignore) "hi")))  => "hi"

如何编写此延续的执行步骤?

3 个答案:

答案 0 :(得分:7)

call/cc运算符用于使用当前延续调用给定过程(因此名称为call-with-current-continuation)。因此,要了解它是如何工作的,我们需要知道当前的延续是什么。

在你的程序中,在执行call/cc时,延续看起来像这样:

CONT = (let ([x HOLE])
         (x (lambda (ignore) "hi")))

其中HOLE是插入值的占位符。换句话说,延续是剩余的计算。如果要进步,可以将值粘贴到延续中。

现在,call/cc捕获此延续并将其传递给过程(lambda (k) k)。您可以看到此过程只是立即返回延续。所以程序简化为:

(let ([x CONT])
  (x (lambda (ignore) "hi")))

应用由call/cc捕获的延续,将当前计算替换为插入了您提供的值的延续。因此应用程序(x (lambda (ignore) "hi"))变为:

(let ([x (lambda (ignore) "hi")])
  (x (lambda (ignore) "hi")))

其余的应该遵循你已经了解的lambda和应用程序。

答案 1 :(得分:3)

在第一行[x (call/cc (lambda (k) k))]中,我们创建了一个新的延续,它与收到的k中的lambda参数绑定。返回k,然后绑定到x局部变量 - 因此,x是一个延续。

在第二行中,使用单参数x调用lambda;参数被忽略,调用(lambda (ignore) "hi")的结果是"hi",最后作为延续的结果返回。这相当于简单地调用:

(call/cc
 (lambda (k)
   (k "hi")))

答案 2 :(得分:1)

为什么这个表达式会评估为“hi”?

(let ([x (call/cc (lambda (k) k))])
  (x (lambda (ignore) "hi")))

第一步是确定k的样子:

(define k
  (lambda (value)
    (let ((x value))
      (x (lambda (ignore) "hi")))))

我们立即看到这与

相同
(define k
  (lambda (x)
    (x (lambda (ignore) "hi"))))

但是,我没有提到一个小细节。如果是k 在调用时,就好像它是在尾部位置调用的。

(f (k 3))构建的所有延续k所以call/cc是。{ 与(k 3)相同。这总是有点棘手。

所以,让我们使用lambda^来表示它引入的功能 被调用就像它处于尾部位置一样。

(define k
  (lambda^ (x)
    (x (lambda (ignore) "hi"))))

现在我们知道k是什么,我们还需要知道返回 (call/cc (lambda (k) k))之外的人确实使用了默认值。

它本应正确编写为

(call/cc (lambda (k) (k k))).

总有一个隐含的k调用位于顶部 lambda表达式的主体传递给call/cc

我们知道k是什么。

所以,我们知道这必须与之相同,(为了便于阅读,我们知道 将参数位置的x转换为y。)

((lambda^ (x) (x (lambda (ignore) "hi")))
 (lambda^ (y) (y (lambda (ignore) "hi"))))

因此,我们评估两个职位的职能。

一旦我们在函数位置调用函数, 我们已经完成了,因为它以lambda^为首,所以,我们需要知道

((lambda^ (x) (x (lambda (ignore) "hi")))
 (lambda^ (y) (y (lambda (ignore) "hi"))))

评估为,取代x

((lambda^ (y) (y (lambda (ignore) "hi")))
 (lambda (ignore) "hi"))

又一步,替换y

导致

((lambda (ignore) "hi") (lambda (ignore) "hi")),忽略了 它的参数并返回“hi”