anchor.diff:  make_list([]) -> cerl:c_nil();
   make_list([H | T]) -> cerl:c_cons(H, make_list(T)).
   
  -translate_seq(First, Next) ->
  -  cerl:c_seq(translate_expr(First), translate_expr(Next)).
  +translate_seq(First, Next, FEnv) ->
  +  cerl:c_seq(translate_expr(First, FEnv), translate_expr(Next, FEnv)).
   
   translate_quote(Value) ->
     %% This is a PRE for cerl:abstract/1, but may not be true for all possible
  
positive.code: assemble_subst([FVar | FVars], Body) ->
    assemble_subst(FVars, cerl:c_let([cerl:c_var(cerl:fname_id(FVar))], FVar, Body)).
  
  translate_let([],  Body) ->
    translate_expr(Body);
  translate_let([{Lhs, Rhs} | Bindings], Body) ->
    cerl:c_let([cerl:c_var(Lhs)], translate_expr(Rhs), translate_let(Bindings, Body)).
  
  translate_locvar(Var) ->
    %% TODO: assumes Var is printable
    cerl:c_var(Var).
  
  translate_primop('ES:APPLY', [Fun | Args]) ->
    CerlActuals = lists:map(fun translate_expr/1, Args),
    case Fun of
      {'ES:PRIMOP', 'ES:COLON', [M, F, {'ES:QUOTE', A}]} when A =:= length(Args) ->
        cerl:c_call(translate_expr(M), translate_expr(F), CerlActuals);
      _ ->
        cerl:c_apply(translate_expr(Fun), CerlActuals)
    end;
  translate_primop(PrimOp, Args0) ->
    CerlArgs = lists:map(fun translate_expr/1, Args0),
    case {PrimOp, CerlArgs} of
      {'ES:COLON', [M, F, A]} -> make_fun(M, F, A);
      {'ES:LIST', _} -> make_list(CerlArgs)
  
negative.code:   CerlModuleName = cerl:c_atom(ModuleName),
    %% Exports: add module_info/0 and module_info/1
    CerlExports = [modinfo0_fname(), modinfo1_fname() | lists:map(fun translate_export/1, Exports)],
    %% Compute a mapping FName -> Arity from the top-level defuns
    FEnv = build_fenv(Defuns),
    %% Translate each top-level (define (f ...) ...)
    %% Also define module_info/0 and module_info/1.
    CerlDefuns = [modinfo0_def(ModuleName), modinfo1_def(ModuleName) |
                  lists:map(fun(Defun) -> translate_defun(Defun, FEnv) end, Defuns)],
    %% Assemble the module.
    cerl:c_module(CerlModuleName, CerlExports, CerlDefuns).
  
  translate_export({F, A}) ->
    cerl:c_fname(F, A).
  
  build_fenv(Defuns) ->
    lists:foldl(fun build_fenv/2, es_env:empty(), Defuns).
  
  build_fenv({'ES:DEFINE', Var, {'ES:LAMBDA', Formals, _Body}}, FEnv) ->
    none = es_env:lookup(FEnv, Var), % assert
    es_env:enter(FEnv, Var, length(Formals)).
  
  translate_defun({'ES:DEFINE', Var, {'ES:LAMBDA', Formals, Body}}, FEnv) ->
    CerlFVar = cerl:c_fname(Var, length(Formals)),
    CerlFun = translate_lambda(Formals, Body, FEnv),
    {CerlFVar, CerlFun}.
  
  translate_expr(AST, FEnv) ->
    case AST of
      {'ES:GLOVAR', Var} ->
        translate_glovar(Var, FEnv);
      {'ES:IF', Pred, Then, Else} ->
        translate_if(Pred, Then, Else, FEnv);
      {'ES:LAMBDA', Formals, Body} ->
        translate_lambda(Formals, Body, FEnv);
      {'ES:LET', Bindings, Body} ->
        translate_let(Bindings, Body, FEnv);
      {'ES:LETREC', Bindings, Body} ->
        translate_letrec(Bindings, Body, FEnv);
      {'ES:LOCVAR', Var} ->
        translate_locvar(Var);
      {'ES:PRIMOP', PrimOp, Actuals} ->
        translate_primop(PrimOp, Actuals, FEnv);
      {'ES:SEQ', First, Next} ->
        translate_seq(First, Next, FEnv);
      {'ES:QUOTE', Value} ->
        translate_quote(Value)
    end.
  
  %% Variable references not bound in their top-level defun become ES:GLOVAR.
  %% In a module they can only reference top-level defuns in the same module.
  %% FEnv records those and lets us construct the required F/N fname.
  translate_glovar(Var, FEnv) ->
    Arity = es_env:get(FEnv, Var),
    cerl:c_fname(Var, Arity).
  
  translate_if(Pred, Then, Else, FEnv) ->
    %% Synthesize "case Pred of false -> Else; _ -> Then end".
    cerl:c_case(translate_expr(Pred, FEnv),
                [cerl:c_clause([cerl:c_atom('false')], translate_expr(Else, FEnv)),
                 cerl:c_clause([wildpat()], translate_expr(Then, FEnv))]).
  
  translate_lambda(Formals, Body, FEnv) ->
    assemble_lambda(translate_formals(Formals), translate_expr(Body, FEnv)).
  
  assemble_lambda(Vars, Body) ->
    cerl:c_fun(Vars, Body).
  