Skip to content

TCO: output closure-free while loop #3183

@matthewleon

Description

@matthewleon

TCO outputs a while loop that calls a function on every iteration, incurring a performance penalty.

An example. Here is the definition of tailRec from purescript-tailrec:

tailRec :: forall a b. (a -> Step a b) -> a -> b
tailRec f = go <<< f
  where
  go (Loop a) = go (f a)
  go (Done b) = b

It compiles to the following:

var tailRec = function (f) {
    var go = function ($copy_v) {
        var $tco_done = false;
        var $tco_result;
        function $tco_loop(v) {
            if (v instanceof Loop) {
                $copy_v = f(v.value0);
                return;
            };
            if (v instanceof Done) {
                $tco_done = true;
                return v.value0;
            };
            throw new Error("Failed pattern match at Control.Monad.Rec.Class line 96, column 3 - line 96, column 25: " + [ v.constructor.name ]);
        };
        while (!$tco_done) {
            $tco_result = $tco_loop($copy_v);
        };
        return $tco_result;
    };
    return function ($53) {
        return go(f($53));
    };
};

In this case, and many others, the $tco_loop function could be inlined into the while loop, simplifying the resulting code and improving its performance.

To be sure, I imagine the TCO behavior was initially created this way with good reason, so there might be some situation where we can't safely get rid of the closure. We should seek to document this.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions