diff options
Diffstat (limited to 'doc/scheme-binding.texi')
-rw-r--r-- | doc/scheme-binding.texi | 206 |
1 files changed, 206 insertions, 0 deletions
diff --git a/doc/scheme-binding.texi b/doc/scheme-binding.texi index b6bbe7447..94d0587bd 100644 --- a/doc/scheme-binding.texi +++ b/doc/scheme-binding.texi @@ -2,6 +2,13 @@ @node Binding Constructs @chapter Definitions and Variable Bindings +@c FIXME::martin: Review me! + +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. + @menu * Top Level:: Top level variable definitions. * Local Bindings:: Local variable bindings. @@ -13,18 +20,217 @@ @node Top Level @section Top Level Variable Definitions +@c FIXME::martin: Review me! + +@cindex variable definition + +On the top level of a program (e.g. when not inside of a procedure +definition or a @code{let}, @code{let*} or @code{letrec} expression), a +definition of the form + +@lisp +(define a 1) +@end lisp + +@noindent +defines a variable called @var{a} and sets it to the value 1. When the +variable already was bound with a @code{define} expression, the above +form is completely equivalent to + +@lisp +(set! a 1) +@end lisp + +@noindent +that means that @code{define} can be used interchangeably with +@code{set!} when at the top level of the REPL or a Scheme source file. +But note that a @code{set!} is not allowed if the variable was not bound +before. + +Attention: definitions inside local binding constructs (@pxref{Local +Bindings}) act differently (@pxref{Internal Definitions}). + @node Local Bindings @section Local Variable Bindings +@c FIXME::martin: Review me! + +@cindex local bindings +@cindex local variables + +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 (@code{let}, @code{let*} and +@code{letrec}), the Scheme language has a block structure like most +other programming languages since the days of @sc{Algol 60}. Readers +familiar to languages like C or Java should already be used to this +concept, but the family of @code{let} expressions has a few properties +which are well worth knowing. + +The first local binding construct is @code{let}. The other constructs +@code{let*} and @code{letrec} are specialized versions for usage wher +using plain @code{let} is a bit inconvenient. + +@deffn syntax let bindings body +@var{bindings} has the form + +@lisp +((@var{variable1} @var{init1}) @dots{}) +@end lisp + +that is zero or more two--element lists of a variable and an arbitrary +expression each. All @var{variable} names must be distinct. + +A @code{let} expression is evaluated as follows. + +@itemize @bullet +@item +All @var{init} expressions are evaluated. + +@item +New storage is allocated for the @var{variables}. + +@item +The values of the @var{init} expressions are stored into the variables. + +@item +The expressions in @var{body} are evaluated in order, and the value of +the last expression is returned as the value of the @code{let} +expression. + +@item +The storage for the @var{variables} is freed. +@end itemize + +The @var{init} expressions are not allowed to refer to any of the +@var{variables}. +@end deffn + +@deffn syntax let* bindings body +Similar to @code{let}, but the variable bindings are performed +sequentially, that means that all @var{init} expression are allowed to +use the variables defined on their left in the binding list. + +A @code{let*} expression can always be expressed with nested @code{let} +expressions. + +@lisp +(let* ((a 1) (b a)) + b) +@equiv{} +(let ((a 1)) + (let ((b a)) + b)) +@end lisp +@end deffn + +@deffn syntax letrec bindings body +Similar to @code{let}, but it is possible to refer to the @var{variable} +from lambda expression created in any of the @var{inits}. That is, +procedures created in the @var{init} expression can recursively refer to +the defined variables. + +@lisp +(letrec ((even? + (lambda (n) + (if (zero? n) + #t + (odd? (- n 1))))) + (odd? + (lambda (n) + (if (zero? n) + #f + (even? (- n 1)))))) + (even? 88)) +@result{} +#t +@end lisp +@end deffn + +There is also an alternative form of the @code{let} form, which is used +for expressing iteration. Because of the use as a looping construct, +this form (the @dfn{named let}) is documented in the section about +iteration (@pxref{while do, Iteration}) @node Internal Definitions @section Internal definitions +@c FIXME::martin: Review me! + +A @code{define} form which appears inside the body of a @code{lambda}, +@code{let}, @code{let*}, @code{letrec} or equivalent expression is +called an @dfn{internal definition}. An internal definition differs +from a top level definition (@pxref{Top Level}), because the definition +is only visible inside the complete body of the enclosing form. Let us +examine the following example. + +@lisp +(let ((frumble "froz")) + (define banana (lambda () (apple 'peach))) + (define apple (lambda (x) x)) + (banana)) +@result{} +peach +@end lisp + +Here the enclosing form is a @code{let}, so the @code{define}s in the +@code{let}--body are internal definitions. Because the scope of the +internal definitions is the @strong{complete} body of the +@code{let}--expression, the @code{lambda}--expression which gets bound +to the variable @code{banana} may refer to the variable @code{apple}, +even thogh it's definition appears lexically @emph{after} the definition +of @code{banana}. This is because a sequence of internal definition +acts as if it were a @code{letrec} expression. + +@lisp +(let () + (define a 1) + (define b 2) + (+ a b)) +@end lisp + +@noindent +is equivalent to + +@lisp +(let () + (letrec ((a 1) (b 2)) + (+ a b))) +@end lisp + +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 @code{set!}, an exception is thrown for internal definitions +with duplicate bindings. + +@c FIXME::martin: The following is required by R5RS, but Guile does not +@c signal an error. Document it anyway, saying that Guile is sloppy? + +@c Internal definitions are only allowed at the beginning of the body of an +@c enclosing expression. They may not be mixed with other expressions. + +@c @lisp +@c (let () +@c (define a 1) +@c a +@c (define b 2) +@c b) +@c @end lisp @node Binding Reflection @section Querying variable bindings +Guile provides a procedure for checking wehther a symbol is bound in the +top level environment. If you want to whether a symbol is locally bound +in expression, you can use the @code{bound?} macro from the module +@code{(ice-9 optargs)}, documented in @ref{Optional Arguments}. + @c NJFIXME explain [env] @deffn primitive defined? sym [env] Return @code{#t} if @var{sym} is defined in the top-level environment. |