方案 R7RS 中加载和包含之间的差异

eat*_*hil 5 lisp scheme r7rs

在方案 R7RS 中,有 aloadinclude形式。

包含描述为:

语义:include 和 include-ci 都采用一个或多个以字符串文字表示的文件名,应用特定于实现的算法来查找相应的文件,按照指定的顺序读取文件的内容,就像重复应用 read 一样,并有效地重新- 将 include 或 include-ci 表达式与包含从文件中读取的内容的 begin 表达式放在一起。两者之间的区别在于 include-ci 读取每个文件,就像它以 #!fold-case 指令开头一样,而 include 则不然。注意:鼓励实现在包含包含文件的目录中搜索文件,并为用户提供一种指定其他目录进行搜索的方法。

负载描述为:

依赖于实现的操作用于将文件名转换为包含Scheme源代码的现有文件的名称。加载过程从文件中读取表达式和定义,并在环境说明符指定的环境中按顺序计算它们。如果省略环境说明符,则假定为(交互环境)。未指定是否打印表达式的结果。加载过程不会影响当前输入端口和当前输出端口返回的值。它返回一个未指定的值。基本原理:为了可移植性,加载必须对源文件进行操作。它对其他类型文件的操作必然因实现而异。

这两种形式的理由是什么?我认为这是历史性的。这两种形式之间有什么重要的语义差异吗?我发现load可以选择包含环境说明符,但include没有。并且include-ci没有直接等效的使用load. 但比较loadinclude单独比较,有什么区别,重要吗?

小智 5

我认为关键的区别在于includeis语法(或者用传统的 Lisp 术语来说,它是一个宏)而load是一个函数。在传统的 Lisp 术语中(在我无法给出的方案术语中会有更正式的定义),这意味着include它在宏扩展时工作,而load在求值时工作。对于具有文件编译器的实现来说,这些时间可能非常不同:宏扩展时间发生在文件编译期间,而评估仅在加载已编译文件时才发生。

因此,如果我们考虑两个文件,f1.scm其中包含

(define foo 1)
(include "f2.scm")
Run Code Online (Sandbox Code Playgroud)

f2.scm含有

(define bar 2)
Run Code Online (Sandbox Code Playgroud)

那么如果您加载或编译 f1.scm它,则与加载或编译包含以下内容的文件完全相同fe.scm

(define foo 1)
(begin
  (define bar 2))
Run Code Online (Sandbox Code Playgroud)

这又与包含相同fe.scm

(define foo 1)
(define bar 2)
Run Code Online (Sandbox Code Playgroud)

特别是,文件的包含发生在宏扩展时,即编译器运行时发生的情况:编译器生成的目标文件(fasl 文件)将包含 和 的编译定义foobar并且不会以任何方式依赖f2.scm于其编译的定义同等现有。

现在考虑f3.scm包含:

(define foo 1)
(load "f2")
Run Code Online (Sandbox Code Playgroud)

(请注意,我假设(load "f2")(与 相反(load "f2.scm"))如果可以找到已编译的文件,则加载它,如果找不到,则加载源文件:我认为这是依赖于实现的)。

加载此文件的源代码将执行与加载相同的操作f1.scm:它将导致foobar被定义。但编译此文件不会:它会生成一个已编译的文件,稍后加载该文件时将尝试加载f2.scm. 如果该文件存在,则在加载时,将加载该文件,并且效果将与情况相同include。如果加载时它不存在,就会发生不好的事情。编译f1.scm不会导致 中的定义f2.scm被编译。


根据您的背景,可能值得将其与 C 系列语言进行比较。所做include的就是#include所做的:它在读取源文件时拼接它们,而在 C 中(如在许多Scheme/Lisp 系统中),这种情况在编译文件时发生。所做的就是在运行时load加载代码,在 C 语言中,您需要通过调用动态链接器或其他东西来完成此操作。


gho*_*osh 2

从历史上看,Lisp 实现并不提供模块系统。

大型程序使用load来运行一组指令,load 函数通过从文件中逐个读取 S 表达式并将其传递给 eval 来运行REPL 脚本。

另一方面,Include用于将从文件读取的代码内联到您的代码中。它不评估代码。

...将 include 或 include-ci 表达式替换为包含从文件中读取的内容的 begin 表达式

添加的“开始”准备从文件中读取的代码以按顺序进行评估。

来源:问题引用、Racket 文档