Evaluation
A Scheme S-expression is evaluated by calling scheme_eval. This function takes an S-expression (as a Scheme_Object *) and a namespace and returns the value of the expression in that namespace.
The function scheme_apply takes a Scheme_Object * that
is a procedure, the number of arguments to pass to the procedure, and
an array of Scheme_Object * arguments. The return value is the
result of the application. There is also a function
scheme_apply_to_list, which takes a procedure and a list
(constructed with scheme_make_pair) and performs the Scheme
apply operation.
The scheme_eval function actually calls scheme_compile followed by scheme_eval_compiled.
6.1 Top-level Evaluation Functions
The functions scheme_eval, scheme_apply, etc., are top-level evaluation functions. Continuation invocations are confined to jumps within a top-level evaluation.
The functions _scheme_eval_compiled, _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 section 7.
6.2 Tail Evaluation
All of MzScheme's built-in functions and syntax support proper tail-recursion. When a new primitive procedure or syntax is added to MzScheme, 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 scheme_tail_apply should be used instead of scheme_apply. When 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 thunk-or
primitive, which takes any number of thunks and performs or on
the results of the thunks, evaluating only as many thunks as
necessary.
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 thunk-or properly implements tail-recursion: if the final
thunk is applied, then the result of thunk-or is the result of
that application, so scheme_tail_apply is used for the final
application.
6.3 Multiple Values
A primitive procedure can return multiple values by returning the result of calling scheme_values. The functions scheme_eval_compiled_multi, scheme_apply_multi, _scheme_eval_compiled_multi, and _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
scheme_multiple_values ``value''. This quasi-value has the
type Scheme_Object *, but it is not a pointer or a
fixnum. When the result of an evaluation or application is
scheme_multiple_values, the number of actual values can be
obtained as scheme_multiple_count and the array of
Scheme_Object * values as scheme_multiple_array. If
any application or evaluation procedure is called, the
scheme_multiple_count and scheme_multiple_array
variables may be modified, but the array previously referenced by
scheme_multiple_array is never re-used and should never be
modified.
The scheme_multiple_count and scheme_multiple_array variables only contain meaningful values when scheme_multiple_values is returned.
6.4 Library Functions
¤ Scheme_Object *scheme_eval(Scheme_Object *expr, Scheme_Env *env)
Evaluates the (uncompiled) S-expression expr in the namespace
env.
¤ Scheme_Object *scheme_eval_compiled(Scheme_Object *obj)
Evaluates the compiled expression obj, which was previously
returned from scheme_compile.
¤ Scheme_Object *scheme_eval_compiled_multi(Scheme_Object *obj)
Evaluates the compiled expression obj, possibly
returning multiple values (see section 6.3).
¤ Scheme_Object *_scheme_eval_compiled(Scheme_Object *obj)
Non-top-level version of scheme_eval_compiled. (See section 6.1.)
¤ Scheme_Object *_scheme_eval_compiled_multi(Scheme_Object *obj)
Non-top-level version of scheme_eval_compiled_multi. (See section 6.1.)
¤ Scheme_Env *scheme_basic_env()
Creates the main namespace for an embedded MzScheme. This procedure must be called before other MzScheme library function (except scheme_make_param). Extensions to MzScheme 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.
¤ Scheme_Object *scheme_make_namespace(int argc, Scheme_Object **argv)
Creates and returns a new namespace. This values can be cast to
Scheme_Env *. It can also be installed in
a parameterization using scheme_set_param with
MZCONFIG_ENV.
When MzScheme is embedded in an application, create the initial namespace with scheme_basic_env before calling this procedure to create new namespaces.
¤ Scheme_Object *scheme_apply(Scheme_Object *f, int c, Scheme_Object **args)
Applies the procedure f to the given arguments.
¤ Scheme_Object *scheme_apply_multi(Scheme_Object *f, int c, Scheme_Object **args)
Applies the procedure f to the given arguments, possibly
returning multiple values (see section 6.3).
¤ Scheme_Object *_scheme_apply(Scheme_Object *f, int c, Scheme_Object **args)
Non-top-level version of scheme_apply. (See section 6.1.)
¤ Scheme_Object *_scheme_apply_multi(Scheme_Object *f, int c, Scheme_Object **args)
Non-top-level version of scheme_apply_multi. (See section 6.1.)
¤ Scheme_Object *scheme_apply_to_list(Scheme_Object *f, Scheme_Object *args)
Applies the procedure f to the list of arguments in args.
¤ Scheme_Object *scheme_eval_string(char *str, Scheme_Env *env)
Reads an S-expression from str and evaluates it in the given
namespace, and it raises an exception if the expression returns
multiple values. The str argument is parsed as a UTF-8-encoded
string of Unicode characters (so plain ASCII is fine).
¤ Scheme_Object *scheme_eval_string_multi(char *str, Scheme_Env *env)
Like scheme_eval_string, but returns scheme_multiple_values when the expression returns multiple values.
¤ Scheme_Object *scheme_eval_string_all(char *str, Scheme_Env *env, int all)
Like scheme_eval_string, but if all is not 0, then
expressions are read and evaluated from str until the end of
the string is reached.
¤ 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.)
¤ Scheme_Object *scheme_tail_apply_no_copy(Scheme_Object *f, int n, Scheme_Object **args)
Like scheme_tail_apply, but the array args is not
copied. Use this only when args has infinite extent and will not
be used again, or when args will certainly not be used again
until the called procedure has returned.
¤ Scheme_Object *scheme_tail_apply_to_list(Scheme_Object *f, Scheme_Object *l)
Applies the procedure as a tail-call.
¤ Scheme_Object *scheme_compile(Scheme_Object *form, Scheme_Env *env)
Compiles the S-expression form in the given namespace. The
returned value can be used with scheme_eval_compiled et al.
¤ Scheme_Object *scheme_expand(Scheme_Object *form, Scheme_Env *env)
Expands all macros in the S-expression form using the given
namespace.
¤ Scheme_Object *scheme_values(int n, Scheme_Object **args)
Returns the given values together as multiple return values. Unless n
is 1, the result will always be scheme_multiple_values.