变量和函数定义的顺序 [英] The Order of Variable and Function Definitions

查看:126
本文介绍了变量和函数定义的顺序的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

为什么呢?

  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)

推荐答案

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

You need to know several things about Racket:

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

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

模块的作用域规则与函数的规则相似,因此从某种意义上讲,这些定义与函数中的定义相似.

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.

球拍从左到右评估定义.在术语表中,您说的是Racket的定义具有letrec*语义;这与某些使用letrec语义的方案不同,在这些方案中,相互递归的定义永不起作用.

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))

它们是在单个作用域中创建的-因此从理论上讲,前向定义在它们的作用域内是有效的.但是实际上无法使用前向引用值,因为在评估实际值之前会得到一个特殊的#<undefined>值.要查看此内容,请尝试运行以下代码:

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)

牢记所有这些,函数内部的引用使事情变得更加宽容.关键是函数的主体要等到函数被调用后才能执行-因此,如果在函数内部发生前向引用,则调用该函数是有效的(=不会出错或#<undefined>)在所有绑定都已初始化之后.这适用于简单的函数定义

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))

使用常规语法糖的定义

(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))

与主流语言中的x = x+1不相同.它们更像是某些语言中的var x = x+1,它将因出现引用未初始化的变量"错误而失败.这是因为define在当前作用域中创建一个 new 绑定,它不会修改"现有的绑定.

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.

这篇关于变量和函数定义的顺序的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆