为什么';公共Lisp中不存在原语“使用当前continuations调用”

为什么';公共Lisp中不存在原语“使用当前continuations调用”,lisp,scheme,common-lisp,continuations,callcc,Lisp,Scheme,Common Lisp,Continuations,Callcc,Scheme提供了一个带有当前延续符的原语调用,通常缩写为call/cc,它在ANSI Common Lisp规范中没有等价物(尽管有一些库尝试实现它们) 有人知道为什么在ANSI Common Lisp规范中不创建类似原语的决定是出于什么原因吗?Scheme的设计基于使用函数调用来替换最常见的控制结构。这就是为什么该方案需要消除尾部调用:它允许将循环转换为递归调用,而不会潜在地耗尽堆栈空间。这种方法的基本方法是延续传球方式 CommonLisp更实用,教学性也更少。它不规定实施策略,也不需要继

Scheme提供了一个带有当前延续符的原语
调用
,通常缩写为
call/cc
,它在ANSI Common Lisp规范中没有等价物(尽管有一些库尝试实现它们)


有人知道为什么在ANSI Common Lisp规范中不创建类似原语的决定是出于什么原因吗?

Scheme的设计基于使用函数调用来替换最常见的控制结构。这就是为什么该方案需要消除尾部调用:它允许将循环转换为递归调用,而不会潜在地耗尽堆栈空间。这种方法的基本方法是延续传球方式


CommonLisp更实用,教学性也更少。它不规定实施策略,也不需要继续实施。

通用Lisp是几种实用(应用)Lisp(因此是“通用”)标准化工作的结果。CL面向现实应用,因此它具有更“特定”的功能(如)而不是
call/cc

Scheme被设计为用于CS教学的小型干净语言,因此它具有基本的
call/cc
,可用于实现其他工具


另请参见

Common Lisp有一个详细的文件编译模型作为标准语言的一部分。该模型支持在一个环境中将程序编译为目标文件,并将其加载到另一个环境中的映像中。这个计划没有可比性。无
eval when
,或
编译文件
加载时间值
或诸如什么是可外化对象之类的概念,编译代码中的语义必须如何与解释代码一致。Lisp有一种内联函数或不内联函数的方法,因此基本上可以非常精确地控制重新加载编译模块时发生的情况

相比之下,直到最近修订Scheme报告之前,Scheme语言在Scheme程序如何分解为多个文件的主题上完全沉默。没有为此提供函数或宏。看看R5R,在下面。您所拥有的只是一个定义非常松散的
load
函数:

可选过程:(加载文件名)

Filename应该是一个字符串,用于命名包含方案源代码的现有文件。load过程从文件中读取表达式和定义,并按顺序计算它们。未指定是否打印表达式的结果。加载过程不影响当前输入端口和当前输出端口返回的值。Load返回一个未指定的值

理由:为了便于移植,load必须对源文件进行操作。它对其他类型文件的操作必然因实现而异

因此,如果这就是您关于如何从模块构建应用程序的愿景的范围,并且所有超出这一范围的细节都留给实现者去解决,那么当然,发明编程语言语义的天空就是极限。部分注意基本原理部分:如果
load
被定义为对源文件进行操作(所有其他操作都是实现者提供的额外优惠),那么它只不过是一种文本包含机制,如C语言中的
#include
,因此,Scheme应用程序实际上只是一个文本体,通过
load
将其物理分布到多个文本文件中

如果您正在考虑向Common Lisp添加任何功能,那么您必须考虑如何将其融入到详细的动态加载和编译模型中,同时保持用户期望的良好性能

如果您正在考虑的功能需要全局、整体的程序优化(系统需要查看所有内容的结构化源代码),以便用户的程序不会运行不良(尤其是不使用该功能的程序),那么它就不会真正运行

特别是关于连续体的语义,有一些问题。在块作用域的通常语义中,一旦我们离开一个作用域并执行清理,它就消失了;我们不能及时回到那个范围,继续计算。CommonLisp在这方面很普通。我们有
unwind protect
构造,它在作用域终止时执行无条件清理操作。这是具有open file等功能的基础,这些功能为块作用域提供了一个open file handle对象,并确保无论块作用域如何终止,该对象都是关闭的。如果某个延续从该作用域中溢出,则该延续不再具有有效文件。当我们离开范围时,我们不能简单地不关闭文件,因为无法保证将永远使用延续;也就是说,我们必须假设范围事实上永远被放弃,并及时清理资源。这种问题的创可贴解决方案是<代码>动态风,它允许我们在块范围内加入和退出处理程序。因此,当块通过继续重新启动时,我们可以重新打开文件。并且不仅重新打开它,而且实际上将流定位在文件中完全相同的位置,以此类推。如果流在解码某个UTF-8字符的中途,我们必须将其置于相同的状态。因此,如果Lisp得到了continuations,它们要么会被各种执行清理(集成不良)的
结构打破,要么这些结构必须获得更复杂的语义

除了继续,还有其他选择。有些连续体的用法是不必要的。本质上,通过闭包或重启可以获得相同的代码组织。此外,还有一个强大的语言/操作系统结构可以与延续相竞争:即线程。而连续体则有其方面