4.2 标识符与绑定
表达式的上下文决定了该表达式中标识符的含义。具体来说,以语言 racket 开始的模块,即
表示从现在起,本指南中描述的标识符属于该模块,其意义为:cons 指代用于创建序对的函数,car 指代用于提取序对中第一个元素的函数, 以此类推。
符号中介绍了标识符的语法。
像 define、lambda 和 let 这类的形式用于将一个含义与一个或更多标识符相关联。即,它们用于 绑定标识符。程序中应用的绑定的部分即为该绑定的作用域。 对于一个给定的表达式,起作用的绑定的集合叫做该表达式的环境。
例如,在
#lang racket (define f (lambda (x) (let ([y 5]) (+ x y)))) (f 10)
中,define 对 f 进行了绑定,lambda 对 x 进行绑定,let 对 y 进行了绑定。f 的绑定的作用域为整个模块;x 的绑定的作用域为 (let ([y 5]) (+ x y)),而 y 的绑定的作用域只是 (+ x y)。(+ x y) 的环境包括 y、x 和 f,以及 racket 中的任何东西。
模块级的 define 只能绑定尚未定义或通过 require 引入到模块中的标识符。然而局部的 define 定义或其它绑定形式仍可为已经绑定的标识符赋予新的局部绑定, 这种绑定会遮蔽既有的绑定。
(define f (lambda (append) (define cons (append "ugly" "confusing")) (let ([append 'this-was]) (list append cons)))) > (f list) '(this-was ("ugly" "confusing"))
同样,模块级的 define 定义也可shadow遮蔽模块语言中的绑定。 例如,racket 模块中的 (define cons 1) 会遮蔽 racket 提供的 cons。故意遮蔽语言中的绑定通常 并不是什么好主意,特别是 cons 这种广泛使用的绑定。 不过遮蔽能够让程序员无须刻意避开语言中每一个隐蔽的绑定。
即便像 define 和 lambda 这样的标识符也可通过绑定拥有新的的意义, 虽然它们拥有的是变换器绑定(意思是它们表示语法形式)而非值绑定。 由于 define 拥有变换器绑定,因此标识符 define 本身无法被用来获取值。然而,define 的正常绑定可以被遮蔽。
再次提醒,用这种方式遮蔽标准绑定通常并不是什么好主意,不过这种能力是 Racket 的灵活性中固有的部分。