The Order of Variable and Function Definitions

倾然丶 夕夏残阳落幕 提交于 2019-12-11 05:04:37

问题


Why is it that:

  1. Function definitions can use definitions defined after it
  2. while variable definitions can't.

For example,

a) the following code snippet is wrong:

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

b) While the following snippet is right:

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

c) Right too :

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

回答1:


You need to know several things about Racket:

  1. In Racket, each file (that starts with #lang) is a module, unlike many (traditional, r5rs) schemes that have no modules.

  2. The scoping rules for modules are similar to the rules for a function, so in a sense, these definitions are similar to definitions in a function.

  3. Racket evaluates definitions from left to right. In scheme lingo you say that Racket's definitions have letrec* semantics; this is unlike some schemes that use letrec semantics where mutually recursive definitions never work.

So the bottom line is that the definitions are all created in the module's environment (similarly in a function, for function-local definitions), and then they are initialized from left to right. Back-references therefore always work, so you can always do something like

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

They are created in a single scope -- so in theory forward definitions are valid in the sense that they're in scope. But actually using a value of a forward-reference is not going to work since you get a special #<undefined> value until the actual value is evaluated. To see this, try to run this code:

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

A module's toplevel is further restricted so that such references are actually errors, which you can see with:

#lang racket
(define a a)

Having all that in mind, things are a bit more lenient with references inside functions. The thing is that the body of a function is not executed until the function is called -- so if a forward reference happens inside a function, it is valid (= won't get an error or #<undefined>) if the function is called after all of the bindings have been initialized. This applies to plain function definitions

(define foo (lambda () a))

definitions that use the usual syntactic sugar

(define (foo) a)

and even other forms that ultimately expand into functions

(define foo (delay a))

With all of these, you won't get any errors by the same rule -- when all uses of the function bodies happen after the definitions were initialized.

One important note, however, is that you shouldn't confuse this kind of initialization with assignment. This means that things like

(define x (+ x 1))

are not equivalent to x = x+1 in mainstream languages. They're more like some var x = x+1 in a language that will fail with some "reference to uninitialized variable" error. This is because define creates a new binding in the current scope, it does not "modify" an existing one.




回答2:


The following is an approximate general Scheme description, an analogy.

Defining a function

(define (f) (g))

is more or less like

f := (lambda () (g))

so the lambda expression is evaluated, and the resulting functional object (usually a closure) is stored in the new variable f being defined. The function g will have to be defined when the function f will be called.

Similarly, (define (h) a) is like h := (lambda () a) so only when the function h will be called, the reference to the variable a will be checked, to find its value.

But

(define a (f))

is like

a := (f)

i.e. the function f has to be called with no arguments, and the result of that call stored in the new variable a being defined. So the function has to be defined already, at that point.

Each definition in a file is executed in sequence, one after another. Each definition is allowed to refer to any of the variables being defined in a file, both above and below it (they are all said to belong to the same scope), but it is allowed to use values of only those variables that are defined above it.

(there is an ambiguity here: imagine you were using a built-in function, say with (define a (+ 1 2)), but were also defining it later on in the file, say (define + -). Is it a definition, or a redefinition? In the first case, which is Racket's choice, use before definition is forbidden. In the second, the "global" value is used in calculating the value of a, and then the function is redefined. Some Schemes may go that route. Thanks go to Eli Barzilay for showing this to me, and to Chris Jester-Young for helping out).



来源:https://stackoverflow.com/questions/19654973/the-order-of-variable-and-function-definitions

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!