(let ([x (call/cc (lambda (k) k))])
(x (lambda (ignore) "hi"))) => "hi"
如何编写此延续的执行步骤?
答案 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”