1 Welcome to PLT Scheme
2 Scheme Essentials
3 Built-In Datatypes
4 Expressions and Definitions
5 Programmer-Defined Datatypes
6 Modules
7 Contracts
8 Input and Output
9 Regular Expressions
10 Exceptions and Control
11 Iterations and Comprehensions
12 Pattern Matching
13 Classes and Objects
14 Units (Components)
15 Reflection and Dynamic Evaluation
16 Macros
17 Performance
18 Running and Creating Executables
19 Compilation and Configuration
20 More Libraries
Bibliography
Index
Version: 4.0.2

 

4.2 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 scheme, as in

  #lang scheme

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.

Symbols 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 scheme

  

  (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 scheme.

A module-level define can bind only identifiers that are not already bound within the module. For example, (define cons 1) is a syntax error in a scheme module, since cons is provided by scheme. 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"))

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

Shadowing standard bindings in this way is rarely a good idea, but the possibility is an inherent part of Scheme’s flexibility.