Sat Jan 23 06:30:56 CET 2010

The `let' form: understanding ANF

The point of extension is this function, which is called both from the
machine primitive _vm_let as from the continuation primitive _kf_let.

It needs to decide whether to create a continuation frame or not.
This is only necessary for closure applications.

static void _let(sc *sc, _ exprs, _ body, _ env) {
    if (NIL == exprs) {
        /* Done: enter new environment. */
        sc->e = env;
        sc->c = body;
    else {
        /* Evaluate next expression. */
        EXTEND_K(kf_let, f);
        sc->c    = _CAR(exprs);
        f->exprs = _CDR(exprs);
        f->body  = body;
        f->env   = env;

However, nested `let' forms are a special case.  They also need to
create continuation frames before evaluation.

So again, assuming `seq' is implemented as `let' (and later optimized
again to not cons needlessly), the _let() function needs to create a
continuation for:

        - another _vm_let() operation

        - a _vm_app() operation with a closure operator

So, the representation needs to be optimized for dispatching:

new frame:
    (let (let ...))
    (let (app-closure ...))

no frame:
    (let (ref ...))
    (let (const ...))
    (let (app-prim ...))
    (let (app-cont ...))

Can the decision to create a continuation frame be moved from the
caller to the callee?  I.e. something like Forth's ENTER?

Meaning: assume that all primitive machine operations simply produce a
value (i.e. go back to the previous representation), but special-case
closure applications and nested let.