3.0 KiB
Identifiers and Binding
The context of an expression determines the meaning of identifiers that
appear in the expression. In particular, starting a module with the
language racket
, as in
#lang
racket
means that, within the module, the identifiers described in this guide
start with the meaning described here: cons
refers to the function
that creates a pair, car
refers to the function that extracts the
first element of a pair, and so on.
+[missing] introduces the syntax of identifiers.
Forms like define
, lambda
, and let
associate a meaning with one or
more identifiers; that is, they bind identifiers. The part of the
program for which the binding applies is the scope of the binding. The
set of bindings in effect for a given expression is the expression’s
environment.
For example, in
#lang racket
(define f
(lambda (x)
(let ([y 5])
(+ x y))))
(f 10)
the define
is a binding of f
, the lambda
has a binding for x
,
and the let
has a binding for y
. The scope of the binding for f
is
the entire module; the scope of the x
binding is (let ([y 5]) (+ x y))
; and the scope of the y
binding is just (+ x y)
. The
environment of (+ x y)
includes bindings for y
, x
, and f
, as
well as everything in racket
.
A module-level define
can bind only identifiers that are not already
defined or require
d into the module. A local define
or other binding
forms, however, can give a new local binding for an identifier that
already has a binding; such a binding shadows the existing binding.
Examples:
(define f
(lambda (append)
(define cons (append "ugly" "confusing"))
(let ([append 'this-was])
(list append cons))))
> (f list)
'(this-was ("ugly" "confusing"))
Similarly, a module-level define
can shadow a binding from the
module’s language. For example, (define cons 1)
in a racket
module
shadows the cons
that is provided by racket
. Intentionally shadowing
a language binding is rarely a good idea—especially for widely used
bindings like cons
—but shadowing relieves a programmer from having to
avoid every obscure binding that is provided by a language.
Even identifiers like define
and lambda
get their meanings from
bindings, though they have transformer bindings (which means that
they indicate syntactic forms) instead of value bindings. Since
define
has a transformer binding, the identifier define
cannot be
used by itself to get a value. However, the normal binding for define
can be shadowed.
Examples:
> define
eval:1:0: define: bad syntax
in: define
> (let ([define 5]) define)
5
Again, shadowing standard bindings in this way is rarely a good idea, but the possibility is an inherent part of Racket’s flexibility.