anchor.diff:      Arity ->
         throw({argument_limit, Arity})
     end.
  -
  -interpret_let(Bindings, Body, Env) ->
  -  interpret(Body, es_env:overlay(Env, interpret_let_bindings(Bindings, Env))).
  -
  -interpret_let_bindings(Bindings, Env) ->
  -  lists:foldl(fun (Binding, NestedEnv) ->
  -		  interpret_let_binding(Binding, Env, NestedEnv)
  -	      end,
  -	      es_env:empty(), Bindings).
  -
  -interpret_let_binding({Var, Expr}, Env, NestedEnv) ->
  -  es_env:enter(NestedEnv, Var, interpret(Expr, Env)).
  -
  -interpret_letrec(Bindings, Body, Env) ->
  -  interpret(Body, es_env:overlay(Env, interpret_letrec_bindings(Bindings, Env))).
  -
  -interpret_letrec_bindings(Bindings, Env) ->
  -  RecEnv2 = lists:foldl(fun (Binding, RecEnv1) ->
  -			    interpret_letrec_binding(Binding, Env, RecEnv1)
  -			end,
  -			es_env:empty(), Bindings),
  -  unfold_recenv(RecEnv2).
  -
  -unfold_recenv(RecEnv) ->
  -  es_env:map(RecEnv,
  -	     fun (_Var, {Formals, Body, Env}) ->
  -		 make_function(
  -		   Formals,
  -		   fun (Actuals) ->
  -		     RecEnv2 = unfold_recenv(RecEnv),
  -		     Env2 = es_env:overlay(Env, RecEnv2),
  -		     interpret_lambda_body(Formals, Actuals, Body, Env2)
  -		   end)
  -	     end).
  -
  -interpret_letrec_binding({Var, Formals, Body}, Env, RecEnv) ->
  -  es_env:enter(RecEnv, Var, {Formals, Body, Env}).
  -
  -interpret_locvar(Var, Env) ->
  -  es_env:get(Env, Var).
  -
  -interpret_primop(PrimOp, Args0, Env) ->
  -  Args = [interpret(Arg, Env) || Arg <- Args0],
  -  case {PrimOp, Args} of
  -    {'ES:APPLY', [F | Rest]} -> do_apply(F, Rest);
  -    {'ES:COLON', [M, F, A]} -> fun M:F/A;
  -    {'ES:LIST', _} -> Args
  -  end.
  -
  -interpret_seq(First, Next, Env) ->
  -  interpret(First, Env),
  -  interpret(Next, Env).
  -
  -interpret_quote(Value) ->
  -  Value.
  
positive.code: %%%   first parsed and converted to an abstract syntax tree (AST),
  %%%   which is then interpreted.  Function closures record their
  %%%   bodies as ASTs, not as S-expressions.
  %%%
  %%% Extensions:
  %%% - (: M F A) is equivalent to Erlang's fun M:F/A
  
  -module(es_eval).
  
  -export([dynamic_eval/1, primitive_eval/1, do_apply/2]).
  
  %%
  
  dynamic_eval(Sexpr) ->
    do_apply(es_gloenv:get_var('eval'), [Sexpr]).
  
  primitive_eval(Sexpr) ->
    interpret(es_parse:toplevel(Sexpr), es_env:empty()).
  
  %% AST interpreter
  
  interpret(AST, Env) ->
    case AST of
  
negative.code: 
  interpret_lambda_body(Formals, Actuals, Body, Env) ->
    interpret(Body, bind_formals(Formals, Actuals, Env)).
  
  interpret_let(Bindings, Body, Env) ->
    interpret(Body, es_env:overlay(Env, interpret_let_bindings(Bindings, Env))).
  
  interpret_let_bindings(Bindings, Env) ->
    lists:foldl(fun ({Var, Expr}, NestedEnv) ->
                  es_env:enter(NestedEnv, Var, interpret(Expr, Env))
                end,
                es_env:empty(), Bindings).
  
  interpret_letrec(Bindings, Body, Env) ->
    interpret(Body, es_env:overlay(Env, interpret_letrec_bindings(Bindings, Env))).
  
  interpret_letrec_bindings(Bindings, Env) ->
    RecEnv2 = lists:foldl(fun ({Var, Formals, Body}, RecEnv1) ->
                            es_env:enter(RecEnv1, Var, {Formals, Body, Env})
                          end,
                          es_env:empty(), Bindings),
    unfold_recenv(RecEnv2).
  
  unfold_recenv(RecEnv) ->
    es_env:map(RecEnv,
               fun (_Var, {Formals, Body, Env}) ->
                   make_function(
                     Formals,
                     fun (Actuals) ->
                       %% The recursive unfolding is delayed until the function is
                       %% applied, making it finite.
                       RecEnv2 = unfold_recenv(RecEnv),
                       Env2 = es_env:overlay(Env, RecEnv2),
                       interpret_lambda_body(Formals, Actuals, Body, Env2)
                     end)
               end).
  
  interpret_locvar(Var, Env) ->
    es_env:get(Env, Var).
  
  interpret_primop(PrimOp, Args0, Env) ->
    Args = [interpret(Arg, Env) || Arg <- Args0],
    case {PrimOp, Args} of
      {'ES:APPLY', [F | Rest]} -> do_apply(F, Rest);
      {'ES:COLON', [M, F, A]} -> fun M:F/A;
      {'ES:LIST', _} -> Args
    end.
  
  interpret_seq(First, Next, Env) ->
    interpret(First, Env),
    interpret(Next, Env).
  
  interpret_quote(Value) ->
    Value.
  
  %% Auxiliary helpers -----------------------------------------------------------
  
  bind_formals([], [], Env) ->
    Env;
  