4.2 标识符与绑定

表达式的上下文决定了该表达式中标识符的含义。具体来说,以语言 racket 开始的模块,即

#lang racket

表示从现在起,本指南中描述的标识符属于该模块,其意义为:cons 指代用于创建序对的函数,car 指代用于提取序对中第一个元素的函数, 以此类推。

+符号中介绍了标识符的语法。

definelambdalet 这类的形式用于将一个含义与一个或更多标识符相关联。即,它们用于 绑定标识符。程序中应用的绑定的部分即为该绑定的作用域。 对于一个给定的表达式,起作用的绑定的集合叫做该表达式的环境

例如,在

#lang racket
 
(define f
  (lambda (x)
    (let ([y 5])
      (+ x y))))
 
(f 10)

中,definef 进行了绑定,lambdax 进行绑定,lety 进行了绑定。f 的绑定的作用域为整个模块;x 的绑定的作用域为 (let ([y 5]) (+ x y)),而 y 的绑定的作用域只是 (+ x y)(+ x y) 的环境包括 yxf,以及 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 这种广泛使用的绑定。 不过遮蔽能够让程序员无须刻意避开语言中每一个隐蔽的绑定。

即便像 definelambda 这样的标识符也可通过绑定拥有新的的意义, 虽然它们拥有的是变换器绑定(意思是它们表示语法形式)而非值绑定。 由于 define 拥有变换器绑定,因此标识符 define 本身无法被用来获取值。然而,define 的正常绑定可以被遮蔽。

例如:
> define

eval:1:0: define: bad syntax

  in: define

> (let ([define 5]) define)

5

再次提醒,用这种方式遮蔽标准绑定通常并不是什么好主意,不过这种能力是 Racket 的灵活性中固有的部分。