回到那天,我以为我明白了call/cc
。这些天来,我看到更多关于“定界”延续运算符的引用,它们似乎成对出现,例如shift
/ reset
,prompt
/ control
,有时甚至更奇特。但是我还没有看到任何基础知识的明确解释,所以
- 他们在做什么?
- 它们是干什么用的?
- 什么可能使一组运算符比另一种更适合特定语言/上下文/目的?
回到那天,我以为我明白了call/cc
。这些天来,我看到更多关于“定界”延续运算符的引用,它们似乎成对出现,例如shift
/ reset
,prompt
/ control
,有时甚至更奇特。但是我还没有看到任何基础知识的明确解释,所以
我已经阅读了几篇文章,我可以解释这个想法。所以我不知道如何实现它以及如何实际使用它,但我理解了主要思想。
假设你有一个电话
(f (h (g x)) 2)
^ << scheme undelimited cont. captures from here
并g
捕获延续。
在scheme中,如果你调用call/cc
within g
,它会从顶层开始复制所有的执行栈(从f
被调用的地方开始)——如果顶层有很多表达式,每个表达式都有自己的stacklet和调用保存的延续将在顶层停止(因此,在上面的表达式中,它将在 f 之后停止,此时它的值为f
)。
如果您希望从内部g
到退出点捕获延续h
,并且每次调用延续都将值返回给 f,那么捕获从调用点开始的堆栈就足够了h
,而不是完整的 stacklet的调用f
,因此您想告诉系统调用类似 call/cc 的函数不要从顶层复制其余计算,而是从给定点复制,并且每次在该点返回一个值:
(f (h (g x)) 2)
^ << delimited cont. captures from here
在这种情况下,您可以对系统进行检测,例如:
(f (shift (h (g x)) 2))
并调用reset
inside g
,在您需要捕获延续的地方。
定界延续可以通过无定界延续来模拟,但我认为在某些情况下能够使用定界更实际。因此,您不能以仅在感兴趣区域中复制堆栈的实用方式在方案中执行此操作,它迫使您复制完整的堆栈(我说“堆栈”而不是堆栈,因为真正的堆栈更大,并且外部链式 stacklet 表示退出代码时执行的初始化代码的延续)。
这些是我从阅读的论文中获得的一些想法。我也有兴趣听到更详细的答案。