在 1990 年代和 2000 年代,编程语言爱好者几乎没有讨论过定界延续的话题。它最近重新成为编程语言讨论中的重要内容。
我希望有人至少可以权威地说明 Rakudo 的延续(与 Raku 相比)是否具有下面列出的六个特征中的每一个。我多说一点关于列表之后我希望得到的那种答案。
从在线消息[1]中逐字引用(带有格式修饰),该消息由推动向 JVM 添加延续工作的人员编写:
非对称:当延续暂停或产生时,执行返回到调用者(的
Continuation.run()
)。对称延续没有调用者的概念。当他们屈服时,他们必须指定另一个延续来将执行转移到。对称延拓和不对称延拓都没有比另一个更强大,并且每个都可以用来模拟另一个。Stackful:延续可以在调用堆栈中的任何深度暂停,而不是在同一子例程中,当延续为无堆栈时(如 C# 中的情况),定界上下文开始。即延续有它自己的堆栈而不是一个单一的子程序帧。堆叠延续比无堆叠延续更强大。
Delimited:延续捕获以特定调用开始的执行上下文(在我们的例子中,是某个可运行的主体),而不是整个执行状态一直到
main()
. 定界延续严格来说比无定界延续更强大(http://okmij.org/ftp/continuations/undelimited.html),后者被认为“没有实际用处”(http://okmij.org/ftp/continuations/against-调用cc.html)。多提示:可以嵌套延续,调用堆栈中的任何位置,任何封闭的延续都可以暂停。这类似于 try/catch 块的嵌套,并抛出某种类型的异常,将堆栈展开到处理它的最近的 catch 而不仅仅是最近的 catch。嵌套延续的一个示例可以是在虚拟线程中使用类似 Python 的生成器。生成器代码可以执行阻塞 IO 调用,这将暂停封闭线程的继续,而不仅仅是生成器:https ://youtu.be/9vupFNsND6o?t=2188
One-shot/non-reentrant:每次我们继续一个暂停的延续时,它的状态都会发生变化,我们不能多次从同一个暂停状态继续它(即我们不能及时返回)。这与可重入延续不同,每次我们挂起它们时,都会返回一个表示特定挂起点的新的不可变延续对象。即延续是一个时间点,每次我们继续它时,我们都会回到那个状态。可重入的延续比不可重入的延续更强大;即,他们可以做一些仅靠一次性延续绝对不可能的事情。
可克隆:如果我们能够克隆一次性延续,我们可以提供与可重入延续相同的能力。即使每次我们继续它都会改变延续,我们可以在继续创建该时间点的快照之前克隆它的状态,以便稍后返回。
Aiui 延续没有直接暴露在 Raku 中,所以与 Raku 相关的正确答案(相对于 Rakudo)可能是“没有延续”。但这对我来说并不清楚,所以在下面,如果我很幸运,我会在其中描述我希望答案中的内容,我会假装在两个 Raku 的背景下谈论它们是有意义的和乐道作为两个不同的领域。
这是我想象的可能的答案(尽管我只是有点疯狂地猜测什么是真的):
“作为“100 年”的语言设计,Raku当前的底层语义 [执行?] 模型至少需要无堆栈的一次性多提示分隔的延续。
从理论上的观点来看,Raku 的设计永远不能扩展到要求延续是可克隆的,但理论上它可以扩展到要求它们是可堆叠的。
Rakudo 实现了当前需要的延续语义。
MoarVM 内置了对这些语义的支持,并且如果 Raku 的设计如此扩展,则可以实际跟踪理论上可能的需求扩展。
JVM 和 JS 后端有合适的 shims 来实现相同的目标,尽管会以性能为代价。JVM 后端可以切换到使用 JVM 原生的 continuation 似乎是合理的,如果它得到它们,当然前提是它们满足要求,但我目前的印象是它可能实际上可能是十年在我们需要考虑过那座桥之前,我们必须离开,或者更多。”
(或类似的东西。)
如果答案还提供了有关上述内容的更多详细信息,也许是一些代码链接,那将是一个特别棒的补充。
类似地,如果答案包括几个简短的例子,说明这种持续能力如何在当前 Raku 功能中出现,以及关于它可能如何在某一天(比如 10 年后)出现在其他功能中的猜测,那么答案就会变得过于——最出色的一个。
PS。感谢@Larry,他对事物的理解足够深入,知道延续需要成为图片的一部分;感谢 Stefan O'Rear 的贡献,包括我认为一次性多提示分隔延续的初步实现;并感谢 jnthn 让梦想成真。
脚注
1将延续作为第一类构造引入 JVM 的工作正在进行中。这一努力的主要推动者是 Ron Pressler。以上是基于他在 11 月写的一条消息。