mattbierner / khepri

ECMAScript derived programming language
http://khepri-lang.com/
MIT License
67 stars 3 forks source link

Better compose generated code #43

Closed mattbierner closed 10 years ago

mattbierner commented 10 years ago

Current:

var f, g;
f <\ g ;

Generates

var f, g;
(function(f, g) {
    return (function(x) {
        return f(g(x));
    });
})(f, g);

Should be:

 (function(x) {
        return f(g(x));
    });
mattbierner commented 10 years ago

Actually the best translation is:

f <\ g;

becomes:

let __f = f, __g = g in f(g(x));

becomes

var f, g;
var __f = f,
    __g = g;
(function(x) {
    return __f(__g(x));
});

This ensures that both f and g are evaluated once and not in the inner function

mattbierner commented 10 years ago

Slightly better in V0.21.4:

var f:= ..., g := ...;
f \> g;

outputs

"use strict";
var f = (function() {
    return 3;
}),
    g = (function(x) {
        return 2;
    }),
    x = f,
    y = g,
    f0 = y,
    g0 = x;
(function(x) {
    return f0(g0(x));
});

The weird x=f, ... repeated bindings are caused by a separate issue. The main benefit is that Instead of two inling functions (one inside of the other) for each compose expression, only a function for each compose appears in the code.

However:

f \> g \> f;

Still requires an extra function call for the generated compose code:

"use strict";
var f = (function() {
    return 3;
}),
    g = (function(x) {
        return 2;
    }),
    x = f,
    x0 = g,
    y = f,
    f0 = y,
    g0 = x0,
    y0 = (function(x) {
        return f0(g0(x));
    }),
    f1 = y0,
    g1 = x;
(function(x) {
    return f1(g1(x));
});
mattbierner commented 10 years ago

Fixed generation of efficient code but not pruning of unreachable funcs:

var f = (+, 10), g = (*, 2) ,z = (_/, 5);

var w = f \> g \> z \>f;

Generates:

var x, x0, x1, y, y0, y1, __divr = (function(x, y) {
        return (y / x);
    }),
    __mul = (function(x, y) {
        return (x * y);
    }),
    __add = (function(x, y) {
        return (x + y);
    }),
    f = (function(y) {
        return (10 + y);
    }),
    g = (function(y) {
        return (2 * y);
    }),
    z = (function(y) {
        return (y / 5);
    }),
    w = ((x = (function(y) {
        return (10 + y);
    })), (x0 = (function(y) {
        return (2 * y);
    })), (x1 = (function(y) {
        return (y / 5);
    })), (y = (function(y0) {
        return (10 + y0);
    })), (y0 = (function(x2) {
        var y1 = x2,
            y2 = (y1 / 5);
        return (10 + y2);
    })), (y1 = (function(x2) {
        var y2 = x2,
            x3 = (2 * y2),
            y3 = x3,
            y4 = (y3 / 5);
        return (10 + y4);
    })), (function(x2) {
        var y2 = x2,
            x3 = (10 + y2),
            y3 = x3,
            x4 = (2 * y3),
            y4 = x4,
            y5 = (y4 / 5);
        return (10 + y5);
    }));

Which obviously is not very good overall but :

function(x2) {
        var y2 = x2,
            x3 = (10 + y2),
            y3 = x3,
            x4 = (2 * y3),
            y4 = x4,
            y5 = (y4 / 5);
        return (10 + y5);
    })

is the correct composition.

The problem is that none of the other unreachable bindings are then pruned, #91.

mattbierner commented 10 years ago

Fixed in V0.21.12

Same input as before:

var f = (+, 10), g = (*, 2) ,z = (_/, 5);

var w = f \> g \> z \>f;

outputs:

use strict";
var __divr = (function(x, y) {
    return (y / x);
}),
    __mul = (function(x, y) {
        return (x * y);
    }),
    __add = (function(x, y) {
        return (x + y);
    }),
    f = (function(y) {
        return (10 + y);
    }),
    g = (function(y) {
        return (2 * y);
    }),
    z = (function(y) {
        return (y / 5);
    }),
    w = (function(x) {
        var x0 = (10 + x),
            x1 = (2 * x0),
            y = (x1 / 5);
        return (10 + y);
    });