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 a single S-expression from str and evaluates it in the given namespace; the expression must return a single value, otherwise an exception is raised. 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.