lambda表达式中的球拍和未绑定标识符,与r5rs形成对比

时间:2015-04-08 16:54:06

标签: lambda scheme racket r5rs

在DrRacket中,当我将语言设置为R5RS并运行以下代码时:

(lambda (x) z)

它运行时没有错误并返回#<procedure>。这对我来说很有意义; lambda表单定义了一个尚未评估其主体的过程,以便返回该过程。

或者,当我使用Racket语言时,我收到以下错误:

z: unbound identifier in module in: z

我不明白为什么Racket会产生这个错误。我的意思是,当然我看到z未定义,但我对评估模型的理解是在函数定义时不评估函数体。这与R5RS结果一致,但与Racket结果无关。什么是球拍在这里做的,确切地说?是否在代码正文中以某种方式“窥视”以查看变量是否已定义? R5RS的评估模型有什么不同导致这种不同的行为?

2 个答案:

答案 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代码做出相同的保证。我只能看到这是一件好事,因为它可以防止源文件中的错误。