在DrRacket中,当我将语言设置为R5RS并运行以下代码时:
(lambda (x) z)
它运行时没有错误并返回#<procedure>
。这对我来说很有意义; lambda表单定义了一个尚未评估其主体的过程,以便返回该过程。
或者,当我使用Racket语言时,我收到以下错误:
z: unbound identifier in module in: z
我不明白为什么Racket会产生这个错误。我的意思是,当然我看到z
未定义,但我对评估模型的理解是在函数定义时不评估函数体。这与R5RS结果一致,但与Racket结果无关。什么是球拍在这里做的,确切地说?是否在代码正文中以某种方式“窥视”以查看变量是否已定义? R5RS的评估模型有什么不同导致这种不同的行为?
答案 0 :(得分:5)
#lang
文件是模块。有关如何扩展和评估模块的规范在文档中有详细描述。经过一番挖掘后,我发现了这个说明:
在任何阶段都不能多次导入或定义标识符 单个模块中的级别。每个导出的标识符必须是 导入或定义。没有表达式可以引用顶级变量。
最后一句“没有表达式可以引用顶级变量。”意味着必须绑定所有变量。
相反,在repl中输入的表达式不是模块,而是任何模块“外部”的表达式。对未绑定变量的引用将成为对顶级变量的引用。在计算表达式时,将在当前名称空间中查找顶级变量的值。如果在查找时,变量没有关联值,则会发出错误信号。
repl使用这个复杂的规则,以允许定义相互递归函数,一次定义一个。
有关REPL的更多信息,请参阅: https://gist.github.com/samth/3083053
答案 1 :(得分:4)
Racket中的源文件
#lang racket
(define f (lambda (x) z))
结果:
z: unbound identifier in module in: z
REPL互动:
Welcome to DrRacket, version 6.1.1 [3m].
Language: racket; memory limit: 128 MB.
> (define f (lambda (x) z))
>
没有错误。
定义了z的源文件:
#lang racket
(define f (lambda (x) z))
(define z 5)
没有错误。
因此,Racket确保定义源文件中的所有变量,而不对REPL代码做出相同的保证。我只能看到这是一件好事,因为它可以防止源文件中的错误。