1

为什么会这样:

  1. 函数定义可以使用它之后定义的定义
  2. 而变量定义不能。

例如,

a) 以下代码段错误:

; Must define function `f` before variable `a`.
#lang racket
(define a (f)) 
(define (f) 10)

b)虽然以下代码段是正确的:

; Function `g` could be defined after function `f`.
#lang racket
(define (f) (g)) ; `g` is not defined yet
(define (g) 10)

c)

; Variable `a` could be defined after function `f`
#lang racket
(define (f) a) ; `a` is not defined yet
(define a 10)
4

2 回答 2

5

您需要了解有关 Racket 的几件事:

  1. 在 Racket 中,每个文件(以 开头#lang)都是一个模块,这与许多没有模块的(传统,r5rs)方案不同。

  2. 模块的作用域规则类似于函数的规则,因此在某种意义上,这些定义类似于函数中的定义。

  3. Racket 从左到右评估定义。在方案行话中,您说 Racket 的定义具有letrec*语义;这与一些使用letrec语义的方案不同,其中相互递归的定义永远不会起作用。

所以底线是定义都是在模块的环境中创建的(类似于在函数中,对于函数局部定义),然后它们从左到右初始化。因此,反向引用总是有效的,所以你总是可以做类似的事情

(define a 1)
(define b (add1 a))

它们是在单个范围内创建的——因此理论上,前向定义在它们在范围内的意义上是有效的。但实际上使用前向引用的值是行不通的,因为在#<undefined>评估实际值之前你会得到一个特殊的值。要看到这一点,请尝试运行以下代码:

#lang racket
(define (foo)
  (define a a)
  a)
(foo)

模块的顶层受到进一步限制,因此此类引用实际上是错误,您可以通过以下方式看到:

#lang racket
(define a a)

考虑到所有这些,对于函数内部的引用来说,事情会更加宽容。问题是函数的主体在函数被调用之前不会执行——所以如果在函数内部发生前向引用,那么它是有效的(= 不会得到错误或#<undefined>)如果函数在所有绑定已初始化。这适用于普通函数定义

(define foo (lambda () a))

使用常用语法糖的定义

(define (foo) a)

甚至最终扩展为功能的其他形式

(define foo (delay a))

有了所有这些,您将不会通过相同的规则得到任何错误——当函数体的所有使用都发生在定义初始化之后。

然而,一个重要的注意事项是,您不应该将这种初始化与赋值混淆。这意味着像

(define x (+ x 1))

等同x = x+1主流语言。它们更像是某种var x = x+1语言中的一些,会因“引用未初始化的变量”错误而失败。这是因为在当前范围内define创建了一个绑定,它不会“修改”现有的绑定。

于 2013-10-29T10:47:45.973 回答
1

下面是一个近似的一般 Scheme 描述,一个类比。

定义一个函数

(define (f) (g))

或多或少像

f := (lambda () (g))

因此计算 lambda 表达式,并将生成的函数对象(通常是闭包)存储在f正在定义的新变量中。必须在调用函数g定义该函数。f

同样,(define (h) a)只有h := (lambda () a)当函数被调用时,才会检查h对变量的引用,以找到它的值。a

(define a (f))

就好像

a := (f)

f必须在没有参数的情况下调用该函数,并且该调用的结果存储在a正在定义的新变量中。所以这个函数必须在那个时候已经定义好了。

文件中的每个定义都按顺序执行,一个接一个。每个定义都可以引用文件中定义的任何变量,包括其上方和下方(它们都被称为属于同一范围,但仅允许使用上面定义的那些变量的它。

(这里有一个歧义:假设您使用的是内置函数,例如 with (define a (+ 1 2)),但稍后也在文件中定义它,例如(define + -)。它是定义还是重新定义?在第一种情况下,这是 Racket 的选择,禁止在定义之前使用。第二,“全局”值用于计算 的值a,然后重新定义函数。一些方案可能会走这条路。感谢 Eli Barzilay 向我展示了这个,并感谢 Chris Jester-Young 的帮助)。

于 2013-10-29T10:24:29.427 回答