Definitions and Variable Bindings
*********************************

Scheme supports the definition of variables in different contexts. Variables can be defined at the top level, so that they are visible in the entire program, and variables can be defined locally to procedures and expressions.  This is important for modularity and data abstraction.

Top Level Variable Definitions
==============================

On the top level of a program (e.g. when not inside of a procedure definition or a let, let* or letrec expression), a definition of the form

     (define a 1)

defines a variable called A and sets it to the value 1.  When the variable already was bound with a define expression, the above form is completely equivalent to

     (set! a 1)

that means that define can be used interchangeably with set! when at the top level of the REPL or a Scheme source file. But note that a set! is not allowed if the variable was not bound before.

Attention: definitions inside local binding constructs (see Local Bindings) act differently (see Internal Definitions).

Local Variable Bindings
=======================

As opposed to definitions at the top level, which are visible in the whole program (or current module, when Guile modules are used), it is also possible to define variables which are only visible in a well-defined part of the program.  Normally, this part of a program will be a procedure or a subexpression of a procedure.

With the constructs for local binding (let, let* and letrec), the Scheme language has a block structure like most other programming languages since the days of ALGOL 60.  Readers familiar to languages like C or Java should already be used to this concept, but the family of let expressions has a few properties which are well worth knowing.

The first local binding construct is let.  The other constructs let* and letrec are specialized versions for usage where using plain let is a bit inconvenient.

 -- syntax: let bindings body
     BINDINGS has the form

          ((VARIABLE1 INIT1) ...)

     that is zero or more two-element lists of a variable and an arbitrary expression each.  All VARIABLE names must be distinct.

     A let expression is evaluated as follows.

       * All INIT expressions are evaluated.

       * New storage is allocated for the VARIABLES.

       * The values of the INIT expressions are stored into the variables.

       * The expressions in BODY are evaluated in order, and the value of the last expression is returned as the value of the let expression.

       * The storage for the VARIABLES is freed.

     The INIT expressions are not allowed to refer to any of the VARIABLES.

 -- syntax: let* bindings body
     Similar to let, but the variable bindings are performed sequentially, that means that all INIT expression are allowed to use the variables defined on their left in the binding list.

     A let* expression can always be expressed with nested let expressions.

          (let* ((a 1) (b a))
             b)
          ==
          (let ((a 1))
            (let ((b a))
              b))

 -- syntax: letrec bindings body
     Similar to let, but it is possible to refer to the VARIABLE from lambda expression created in any of the INITS.  That is, procedures created in the INIT expression can recursively refer to the defined variables.

          (letrec ((even?
                    (lambda (n)
                        (if (zero? n)
                            #t
                            (odd? (- n 1)))))
                   (odd?
                    (lambda (n)
                        (if (zero? n)
                            #f
                            (even? (- n 1))))))
            (even? 88))
          =>
          #t

There is also an alternative form of the let form, which is used for expressing iteration.  Because of the use as a looping construct, this form (the named let) is documented in the section about iteration (see Iteration)

Internal definitions
====================

A define form which appears inside the body of a lambda, let, let*, letrec or equivalent expression is called an internal definition.  An internal definition differs from a top level definition (see Top Level), because the definition is only visible inside the complete body of the enclosing form.  Let us examine the following example.

     (let ((frumble "froz"))
        (define banana (lambda () (apple 'peach)))
        (define apple (lambda (x) x))
        (banana))
     =>
     peach

Here the enclosing form is a let, so the defines in the let-body are internal definitions.  Because the scope of the internal definitions is the complete body of the let-expression, the lambda-expression which gets bound to the variable banana may refer to the variable apple, even thogh it's definition appears lexically after the definition of banana.  This is because a sequence of internal definition acts as if it were a letrec expression.

     (let ()
       (define a 1)
       (define b 2)
       (+ a b))

is equivalent to

     (let ()
       (letrec ((a 1) (b 2))
         (+ a b)))

Another noteworthy difference to top level definitions is that within one group of internal definitions all variable names must be distinct. That means where on the top level a second define for a given variable acts like a set!, an exception is thrown for internal definitions with duplicate bindings.

Querying variable bindings
==========================

Guile provides a procedure for checking wehther a symbol is bound in the top level environment.  If you want to test whether a symbol is locally bound in expression, you can use the bound? macro from the module (ice-9 optargs), documented in Optional Arguments.

 -- primitive: defined? sym [env]
     Return #t if SYM is defined in the top-level environment.