letrec* in docs, and some r6rs fixes

* doc/ref/api-binding.texi: Add docs for letrec*, and revise some other
  text.
* doc/ref/compiler.texi: Update <letrec> for in-order?.
* doc/ref/r6rs.texi: Add letrec* entry.

* module/rnrs.scm:
* module/rnrs/base.scm: Export letrec*.
This commit is contained in:
Andy Wingo 2010-08-06 11:52:27 +02:00
commit 935c7acac7
5 changed files with 92 additions and 70 deletions

View file

@ -1,14 +1,12 @@
@c -*-texinfo-*-
@c This is part of the GNU Guile Reference Manual.
@c Copyright (C) 1996, 1997, 2000, 2001, 2002, 2003, 2004, 2009
@c Copyright (C) 1996, 1997, 2000, 2001, 2002, 2003, 2004, 2009, 2010
@c Free Software Foundation, Inc.
@c See the file guile.texi for copying conditions.
@node Binding Constructs
@section 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
@ -27,8 +25,7 @@ and expressions. This is important for modularity and data abstraction.
@cindex variable definition
On the top level of a program (i.e. when not inside the body of a
procedure definition or a @code{let}, @code{let*} or @code{letrec}
At the top level of a program (i.e., not nested within any other
expression), a definition of the form
@lisp
@ -38,10 +35,10 @@ expression), a definition of the form
@noindent
defines a variable called @code{a} and sets it to the value @var{value}.
If the variable already exists, because it has already been created by a
previous @code{define} expression with the same name, its value is
simply changed to the new @var{value}. In this case, then, the above
form is completely equivalent to
If the variable already exists in the current module, because it has
already been created by a previous @code{define} expression with the
same name, its value is simply changed to the new @var{value}. In this
case, then, the above form is completely equivalent to
@lisp
(set! a @var{value})
@ -95,27 +92,23 @@ Attention: Scheme definitions inside local binding constructs
@node Local Bindings
@subsection 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.
As opposed to definitions at the top level, which creates bindings that
are visible to all code in a module, 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.
With the constructs for local binding (@code{let}, @code{let*},
@code{letrec}, 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 where
using plain @code{let} is a bit inconvenient.
The most basic local binding construct is @code{let}.
@deffn syntax let bindings body
@var{bindings} has the form
@ -143,15 +136,16 @@ The values of the @var{init} expressions are stored into the variables.
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
The other binding contructs are variations on the same theme: making new
values, binding them to variables, and executing a body in that new,
extended lexical context.
@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
@ -177,13 +171,11 @@ procedures created in the @var{init} expression can recursively refer to
the defined variables.
@lisp
(letrec ((even?
(lambda (n)
(letrec ((even? (lambda (n)
(if (zero? n)
#t
(odd? (- n 1)))))
(odd?
(lambda (n)
(odd? (lambda (n)
(if (zero? n)
#f
(even? (- n 1))))))
@ -191,6 +183,33 @@ the defined variables.
@result{}
#t
@end lisp
Note that while the @var{init} expressions may refer to the new
variables, they may not access their values. For example, making the
@code{even?} function above creates a closure (@pxref{About Closure})
referencing the @code{odd?} variable. But @code{odd?} can't be called
until after execution has entered the body.
@end deffn
@deffn syntax letrec* bindings body
Similar to @code{letrec}, except the @var{init} expressions are bound to
their variables in order.
@code{letrec*} thus relaxes the letrec restriction, in that later
@var{init} expressions may refer to the values of previously bound
variables.
@lisp
(letrec ((a 42)
(b (+ a 10)))
(* a b))
@result{} ;; Error: unbound variable: a
(letrec* ((a 42)
(b (+ a 10)))
(* a b))
@result{} 2184
@end lisp
@end deffn
There is also an alternative form of the @code{let} form, which is used
@ -204,11 +223,11 @@ iteration (@pxref{while do, Iteration})
@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.
@code{let}, @code{let*}, @code{letrec}, @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"))
@ -222,11 +241,11 @@ peach
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 though 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.
@code{let}-expression, the @code{lambda}-expression which gets bound to
the variable @code{banana} may refer to the variable @code{apple}, even
though its 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 ()
@ -240,29 +259,36 @@ is equivalent to
@lisp
(let ()
(letrec ((a 1) (b 2))
(letrec* ((a 1) (b 2))
(+ a b)))
@end lisp
Internal definitions are only allowed at the beginning of the body of an
enclosing expression. They may not be mixed with other expressions.
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?
As a historical note, it used to be that internal bindings were expanded
in terms of @code{letrec}, not @code{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:
@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.
@lisp
(let ()
(define a 1)
(define b (+ a a))
(+ a b))
@end lisp
@noindent
Guile decided to follow the R6RS in this regard, and now expands
internal definitions using @code{letrec*}.
@c @lisp
@c (let ()
@c (define a 1)
@c a
@c (define b 2)
@c b)
@c @end lisp
@node Binding Reflection
@subsection Querying variable bindings
@ -275,11 +301,6 @@ top level environment.
Return @code{#t} if @var{sym} is defined in the module @var{module} or
the current module when @var{module} is not specified; otherwise return
@code{#f}.
Up to Guile 1.8, the second optional argument had to be @dfn{lexical
environment} as returned by @code{the-environment}, for example. The
behavior of this function remains unchanged when the second argument is
omitted.
@end deffn

View file

@ -441,10 +441,10 @@ original binding names, @var{gensyms} are gensyms corresponding to the
@var{names}, and @var{vals} are Tree-IL expressions for the values.
@var{exp} is a single Tree-IL expression.
@end deftp
@deftp {Scheme Variable} <letrec> src names gensyms vals exp
@deftpx {External Representation} (letrec @var{names} @var{gensyms} @var{vals} @var{exp})
@deftp {Scheme Variable} <letrec> in-order? src names gensyms vals exp
@deftpx {External Representation} (letrec @var{in-order?} @var{names} @var{gensyms} @var{vals} @var{exp})
A version of @code{<let>} that creates recursive bindings, like
Scheme's @code{letrec}.
Scheme's @code{letrec}, or @code{letrec*} if @var{in-order?} is true.
@end deftp
@deftp {Scheme Variable} <dynlet> fluids vals body
@deftpx {External Representation} (dynlet @var{fluids} @var{vals} @var{body})

View file

@ -233,6 +233,7 @@ grouped below by the existing manual sections to which they correspond.
@deffn {Scheme Syntax} let bindings body
@deffnx {Scheme Syntax} let* bindings body
@deffnx {Scheme Syntax} letrec bindings body
@deffnx {Scheme Syntax} letrec* bindings body
@xref{Local Bindings}, for documentation.
@end deffn

View file

@ -52,7 +52,7 @@
boolean? symbol? char? vector? null? pair? number? string? procedure?
define define-syntax syntax-rules lambda let let* let-values
let*-values letrec begin quote lambda if set! cond case or and not
let*-values letrec letrec* begin quote lambda if set! cond case or and not
eqv? equal? eq? + - * / max min abs numerator denominator gcd lcm
floor ceiling truncate round rationalize real-part imag-part
make-rectangular angle div mod div-and-mod div0 mod0 div0-and-mod0

View file

@ -21,7 +21,7 @@
(export boolean? symbol? char? vector? null? pair? number? string? procedure?
define define-syntax syntax-rules lambda let let* let-values
let*-values letrec begin
let*-values letrec letrec* begin
quote lambda if set! cond case