在表达式(call/cc (lambda (k) (k 12)))
中,有三个延续:(k 12)
,(lambda (k) (k 12))
和(call/cc (lambda (k) (k 12)))
。哪一个是“当前的延续”?
某些书籍中的延续被视为等待某个值的过程,当它应用于某个值时会立即返回。是吗?
任何人都可以详细解释当前的延续吗?
答案 0 :(得分:2)
(k 12)
之类的东西不是延续。在一些较大的程序中,每个子表达都有一个延续。例如,x
中(* 3 (+ x 42))
的延续为(lambda (_) (* 3 (+ _ 42)))
。
在您的示例中,(call/cc (lambda (k) (k 12)))
的“当前延续”将是围绕该表达式的任何内容。如果您只是将其输入到方案提示中,那么它周围没有任何内容,因此“当前延续”只是(lambda (_) _)
。如果您输入(* 3 (+ (call/cc (lambda (k) (k 12))) 42))
之类的内容,则续集为(lambda (_) (* 3 (+ _ 42)))
。
请注意,我用来表示“当前延续”的lambdas与call/cc
传入的lambda不同(在您的示例中名为k
)。 k
具有特殊的控制效果,在评估当前延续时中止其余的计算。
答案 1 :(得分:1)
这种情况下的延续是接收call/cc
调用的返回值的“事物”。因此:
(display (call/cc (lambda (k) (k 12)))
与
具有相同的结果(display 12)
Scheme中的延续“外观和感觉”就像程序一样,但它们实际上并不像程序那样。有助于您更好地理解延续的一件事是CPS转换。
在CPS转换中,而不是返回值的函数,而是采用continuation参数,并使用结果调用continuation。因此,CPS转换的sqrt
函数将使用(sqrt 64 k)
调用,而不是返回8,它只是在尾部位置调用(k 8)
。
因为延续(在CPS转换函数中)是尾调用的,所以函数不必担心继续返回,事实上,在大多数情况下,它们不会返回。
考虑到这一点,这是一个函数的简单示例:
(define (hypot x y)
(sqrt (+ (* x x) (* y y))))
及其CPS转换版本:
(define (hypot x y k)
(* x x (lambda (x2)
(* y y (lambda (y2)
(+ x2 y2 (lambda (sum)
(sqrt sum k))))))))
(假设*
,+
和sqrt
都已进行了CPS转换,接受延续参数。)
现在,有趣的部分:CPS转换的call/cc
具有以下定义:
(define (call/cc fn k)
(fn k k))
通过CPS转换,call/cc
易于理解且易于实施。如果没有CPS转换,call/cc
可能需要一个非常神奇的实现(例如,通过堆栈复制等)。