Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

Taking a look now. A couple of questions:

* Why give literal ints their own temporaries? * Why not support lambda expressions? Is it tricky in this approach or just accidentally missing?



> Why give literal ints their own temporaries?

Just following the paper's convention (their justification being that now they only need to substitute variables for variables which is simpler), plus this gist is a trimmed down version of my hobby project which had full-blown algebraic data types: the integers were handled by that case as well. You absolutely can merge "int" case with the "var" case above, and use ints as themselves:

    if isinstance(expr, str) or isinstance(expr, int):
        result = CpsExprBuilder()
        return maybe_tail(result, expr)
The second argument in maybe_tail would need a better name though...

> Why not support lambda expressions?

They were missing in your write-up as well :) I just went by your text, and look at the code snippets in it. But adding them looks like this:

    if what == 'lambda':
        args, body = rest
        result = CpsExprBuilder()
        tmp_name, ret = gen_tmp(), gen_cont()
        fun = ['fun', [*args, ret], cps(body, ret)]
        result.add_let_without_body([[tmp_name, fun]])
        return maybe_tail(result, tmp_name)
Some test cases I've tried look like this then:

    ['lambda', ['x'], 'x'] =>
    let
      #t0 = fun(x, @k1):
        $ret @k1(x)
    in $ret @halt(#t0)
    
    [['lambda', ['x'], 'x'], 2] =>
    let
      #t0 = fun(x, @k1):
        $ret @k1(x)
      #t2 = 2
    in #t0(#t2, @halt)
    
    ['let', ['f', ['lambda', ['x'], 'x']], ['f', 2]] =>
    let
      @k0 = cont(f):
        let
          #t3 = 2
        in f(#t3, @halt)
      #t1 = fun(x, @k2):
        $ret @k2(x)
    in $ret @k0(#t1)
By the way, if you don't like creating contiunations just to immediately invoke them, you can adjust make_LET adjusted to flatten that pattern as well: check if the body is '$ret' with the continuation name that's in the defns list, replace body with this continuation's body (with variables substituted!) and throw its definition away.

    [['lambda', ['x'], 'x'], 2] =>
    let
      #t0 = fun(x, @k1):
        $ret @k1(x)
      #t2 = 2
    in #t0(#t2, @halt)
    
    ['let', ['f', ['lambda', ['x'], 'x']], ['f', 2]] =>
    let
      #t1 = fun(x, @k2):
        $ret @k2(x)
      #t3 = 2
    in #t1(#t3, @halt)
But this also throws the programmer-supplied names away during the substitution, sadly. Preferring to keep programmer-supplied names is possible, of course, but it requires both tracking them and making sure they don't collide with temporaries or other programmer-supplied names so... this simplification step is better performed in the optimizer after the CPS-conversion.


I'll get back to this in more detail soon, but I did have lambda expressions in my blog post...




Consider applying for YC's Winter 2026 batch! Applications are open till Nov 10

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: