A define
form which appears inside the body of a lambda
,
let
, let*
, letrec
, letrec*
or equivalent
expression is called an internal definition. An internal
definition differs from a top level definition (see Top Level Variable Definitions),
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 define
s 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
though its 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)))
Internal definitions may be mixed with non-definition expressions. If an expression precedes a definition, it is treated as if it were a definition of an unreferenced variable. So this:
(let () (define a 1) (foo) (define b 2) (+ a b))
is equivalent to
(let () (letrec* ((a 1) (_ (begin (foo) #f)) (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.
Whereas on the top level a second define for a given variable acts like
a set!
, for internal definitions, duplicate bound identifiers
signals an error.
As a historical note, it used to be that internal bindings were expanded
in terms of letrec
, not letrec*
. This was the situation
for the R5RS report and before. However with the R6RS, it was recognized
that sequential definition was a more intuitive expansion, as in the
following case:
(let () (define a 1) (define b (+ a a)) (+ a b))
Guile decided to follow the R6RS in this regard, and now expands
internal definitions using letrec*
. Relatedly, it used to be
that internal definitions had to precede all expressions in the body;
this restriction was relaxed in Guile 3.0.