racket/collects/scribblings/inside/eval.scrbl
Eli Barzilay 1cbf54d70a fixes for the fixes
svn: r11450
2008-08-27 07:12:35 +00:00

302 lines
11 KiB
Racket

#lang scribble/doc
@(require "utils.ss")
@title{Evaluation}
A Scheme S-expression is evaluated by calling @cppi{scheme_eval}.
This function takes an S-expression (as a @cpp{Scheme_Object*}) and a
namespace and returns the value of the expression in that namespace.
The function @cppi{scheme_apply} takes a @cpp{Scheme_Object*} that is
a procedure, the number of arguments to pass to the procedure, and an
array of @cpp{Scheme_Object *} arguments. The return value is the
result of the application. There is also a function
@cppi{scheme_apply_to_list}, which takes a procedure and a list
(constructed with @cppi{scheme_make_pair}) and performs the Scheme
@scheme[apply] operation.
The @cppi{scheme_eval} function actually calls @cppi{scheme_compile}
followed by @cppi{scheme_eval_compiled}.
@; ----------------------------------------------------------------------
@section[#:tag "topleveleval"]{Top-level Evaluation Functions}
The functions @cpp{scheme_eval}, @cpp{scheme_apply}, etc., are
@defterm{top-level evaluation functions}. Continuation invocations are
confined to jumps within a top-level evaluation.
The functions @cppi{_scheme_eval_compiled}, @cppi{_scheme_apply},
etc. (with a leading underscore) provide the same functionality
without starting a new top-level evaluation; these functions should
only be used within new primitive procedures. Since these functions
allow full continuation hops, calls to non-top-level evaluation
functions can return zero or multiple times.
Currently, escape continuations and primitive error escapes can jump
out of all evaluation and application functions. For more information,
see @secref["exceptions"].
@; ----------------------------------------------------------------------
@section{Tail Evaluation}
@section-index{tail recursion}
All of Scheme's built-in functions and syntax support proper
tail-recursion. When a new primitive procedure or syntax is added to
Scheme, special care must be taken to ensure that tail recursion is
handled properly. Specifically, when the final return value of a
function is the result of an application, then
@cppi{scheme_tail_apply} should be used instead of
@cppi{scheme_apply}. When @cppi{scheme_tail_apply} is called, it
postpones the procedure application until control returns to the
Scheme evaluation loop.
For example, consider the following implementation of a
@scheme[thunk-or] primitive, which takes any number of thunks and
performs @scheme[or] on the results of the thunks, evaluating only as
many thunks as necessary.
@verbatim{
static Scheme_Object *
thunk_or (int argc, Scheme_Object **argv)
{
int i;
Scheme_Object *v;
if (!argc)
return scheme_false;
for (i = 0; i < argc - 1; i++)
if (SCHEME_FALSEP((v = _scheme_apply(argv[i], 0, NULL))))
return v;
return scheme_tail_apply(argv[argc - 1], 0, NULL);
}
}
This @scheme[thunk-or] properly implements tail-recursion: if the
final thunk is applied, then the result of @scheme[thunk-or] is the
result of that application, so @cppi{scheme_tail_apply} is used for
the final application.
@; ----------------------------------------------------------------------
@section[#:tag "multiple"]{Multiple Values}
A primitive procedure can return multiple values by returning the
result of calling @cppi{scheme_values}. The functions
@cppi{scheme_eval_compiled_multi}, @cppi{scheme_apply_multi},
@cppi{_scheme_eval_compiled_multi}, and @cppi{_scheme_apply_multi}
potentially return multiple values; all other evaluation and
applications procedures return a single value or raise an exception.
Multiple return values are represented by the
@cppi{scheme_multiple_values} ``value.'' This quasi-value has the type
@cpp{Scheme_Object*}, but it is not a pointer or a fixnum. When the
result of an evaluation or application is
@cppi{scheme_multiple_values}, the number of actual values can be
obtained as @cppi{scheme_multiple_count}, and the array of
@cpp{Scheme_Object*} values as @cppi{scheme_multiple_array}. (Both of
those identifiers are actually macros.)
A garbage collection must not occur between the return of a
@cppi{scheme_multiple_values} ``value'' and the receipt of the values
through @cppi{scheme_multiple_count} @cppi{scheme_multiple_array}.
Furthermore, if @cpp{scheme_multiple_array} is to be used across a
potential garbage collection, then it must be specifically received by
calling @cpp{scheme_detach_multiple_array}; otherwise, a garbage
collection or further evaluation may change the content of the array.
Otherwise, if any application or evaluation procedure is called, the
@cpp{scheme_multiple_count} and @cpp{scheme_multiple_array} variables
may be modified (but the array previously referenced by
@cpp{scheme_multiple_array} is never re-used if
@cpp{scheme_detatch_multiple_array} is called).
The @cpp{scheme_multiple_count} and
@cpp{scheme_multiple_array} variables only contain meaningful values
when @cpp{scheme_multiple_values} is returned.
@; ----------------------------------------------------------------------
@section{Evaluation Functions}
@function[(Scheme_Object* scheme_eval
[Scheme_Object* expr]
[Scheme_Env* env])]{
Evaluates the (uncompiled) S-expression @var{expr} in the namespace
@var{env}.}
@function[(Scheme_Object* scheme_eval_compiled
[Scheme_Object* obj]
[Scheme_Env* env])]{
Evaluates the compiled expression @var{obj}, which was previously
returned from @cpp{scheme_compile}, first linking to the namespace @var{env}.}
@function[(Scheme_Object* scheme_eval_compiled_multi
[Scheme_Object* obj]
[Scheme_Env* env])]{
Evaluates the compiled expression @var{obj}, possibly
returning multiple values (see @secref["multiple"]).}
@function[(Scheme_Object* _scheme_eval_compiled
[Scheme_Object* obj]
[Scheme_Env* env])]{
Non-top-level version of @cpp{scheme_eval_compiled}. (See @secref["topleveleval"].)}
@function[(Scheme_Object* _scheme_eval_compiled_multi
[Scheme_Object* obj]
[Scheme_Env* env])]{
Non-top-level version of @cpp{scheme_eval_compiled_multi}. (See @secref["topleveleval"].)}
@function[(Scheme_Env* scheme_basic_env)]{
Creates the main namespace for an embedded PLT Scheme. This procedure
must be called before other Scheme library function (except
@cpp{scheme_make_param}). Extensions to Scheme cannot call this
function.
If it is called more than once, this function resets all threads
(replacing the main thread), parameters, ports, namespaces, and
finalizations.}
@function[(Scheme_Object* scheme_make_namespace
[int argc]
[Scheme_Object** argv])]{
Creates and returns a new namespace. This values can be cast to
@cpp{Scheme_Env *}. It can also be installed in
a parameterization using @cppi{scheme_set_param} with
@cppi{MZCONFIG_ENV}.
When PLT Scheme is embedded in an application, create the initial
namespace with @cppi{scheme_basic_env} before calling this procedure
to create new namespaces.}
@function[(Scheme_Object* scheme_apply
[Scheme_Object* f]
[int c]
[Scheme_Object** args])]{
Applies the procedure @var{f} to the given arguments.}
@function[(Scheme_Object* scheme_apply_multi
[Scheme_Object* f]
[int c]
[Scheme_Object** args])]{
Applies the procedure @var{f} to the given arguments, possibly
returning multiple values (see @secref["multiple"]).}
@function[(Scheme_Object* _scheme_apply
[Scheme_Object* f]
[int c]
[Scheme_Object** args])]{
Non-top-level version of @cpp{scheme_apply}. (See @secref["topleveleval"].)}
@function[(Scheme_Object* _scheme_apply_multi
[Scheme_Object* f]
[int c]
[Scheme_Object** args])]{
Non-top-level version of @cpp{scheme_apply_multi}. (See @secref["topleveleval"].)}
@function[(Scheme_Object* scheme_apply_to_list
[Scheme_Object* f]
[Scheme_Object* args])]{
Applies the procedure @var{f} to the list of arguments in @var{args}.}
@function[(Scheme_Object* scheme_eval_string
[char* str]
[Scheme_Env* env])]{
Reads a single S-expression from @var{str} and evaluates it in the given
namespace; the expression must return a single value, otherwise an
exception is raised. The @var{str} argument is parsed as a
UTF-8-encoded string of Unicode characters (so plain ASCII is fine).}
@function[(Scheme_Object* scheme_eval_string_multi
[char* str]
[Scheme_Env* env])]{
Like @cpp{scheme_eval_string}, but returns
@cpp{scheme_multiple_values} when the expression returns multiple
values.}
@function[(Scheme_Object* scheme_eval_string_all
[char* str]
[Scheme_Env* env]
[int all])]{
Like @cpp{scheme_eval_string}, but if @var{all} is not @cpp{0}, then
expressions are read and evaluated from @var{str} until the end of
the string is reached.}
@function[(Scheme_Object* scheme_tail_apply
[Scheme_Object* f]
[int n]
[Scheme_Object** args])]{
Applies the procedure as a tail-call. Actually, this function just
registers the given application to be invoked when control returns to
the evaluation loop. (Hence, this function is only useful within a
primitive procedure that is returning to its caller.)}
@function[(Scheme_Object* scheme_tail_apply_no_copy
[Scheme_Object* f]
[int n]
[Scheme_Object** args])]{
Like @cpp{scheme_tail_apply}, but the array @var{args} is not
copied. Use this only when @var{args} has infinite extent and will not
be used again, or when @var{args} will certainly not be used again
until the called procedure has returned.}
@function[(Scheme_Object* scheme_tail_apply_to_list
[Scheme_Object* f]
[Scheme_Object* l])]{
Applies the procedure as a tail-call.}
@function[(Scheme_Object* scheme_compile
[Scheme_Object* form]
[Scheme_Env* env]
[int writable])]{
Compiles the S-expression @var{form} in the given namespace. The
returned value can be used with @cpp{scheme_eval_compiled} et al.
Provide a non-zero value fo @var{writable} if the resulting compiled
object will be marshalled via @scheme[write] instead of evaluated.}
@function[(Scheme_Object* scheme_expand
[Scheme_Object* form]
[Scheme_Env* env])]{
Expands all macros in the S-expression @var{form} using the given
namespace.}
@function[(Scheme_Object* scheme_values
[int n]
[Scheme_Object** args])]{
Returns the given values together as multiple return values. Unless
@var{n} is @cpp{1}, the result will always be
@cpp{scheme_multiple_values}.}
@function[(void scheme_detach_multiple_array
[Scheme_Object** args])]{
Called to receive multiple-value results; see @secref["multiple"].}