memoize continuation passing style function

2019-04-08 18:19发布

I'm wondering if there is a way to implement a generic "memoize" functional (as in a function with a function as input and a function as output, as python's decorators) capable of handling also cps-style functions.

for a normal function (as in "the result value comes back by the return, the parameters are only for input!") a memoize function can be as simple as (in javascript)

function memoize(fun) {
    var cache = {};
    return function () {
        var args = Array.prototype.slice.call(arguments);
        if (args in cache)
            return cache[args];
        var ret = fun.apply(this, arguments);
        cache[args] = ret;
        return ret;
    };
}

but a cps-style function cannot be memoized by my simple memoize function, cause I need to evaluate "again" the arguments of type function, knowing also the parameter to pass to them.

For example, given the function

function cps(param, next) {
    var ret = param + 1;

    // setTimeout for simulate async behaviour
    setTimeout(function () {
            next(ret);
    }, 0);
}

maybe I can find that next is a function, but its signature (well... maybe, but it's tricky), and definitely not the parameters used in the function!

Can someone tell me I'm wrong? :D

I'm interested to be able to memoize an half dozen of cps-style functions and I don't want to mess with the logic inserting a "cache" in every one of them.

1条回答
狗以群分
2楼-- · 2019-04-08 19:11

I'm new to CPS, but I think you'll have to construct your functions in a particular way.

Your CPS functions have the following structure (generalising from your example):

function cps(param, next) {
    var ret = someFunctionOfParam(param);

    // setTimeout for simulate async behaviour
    setTimeout(function () {
        next(ret);
    }, 0);
}

So, you could use your standard memoizer, and construct the CPS function as well. Keeping this separate for the sake of it, first the CPS-maker (assumes the last argument for the functions is always the function to pass to):

function cpsMaker(transformFunc) {
    return function() {
               var args = Array.prototype.slice.call(arguments);
               var next = args.pop(); // assume final arg is function to call
               var ret = transformFunc.apply(this,args);
               // setTimeout for simulate async behaviour
               setTimeout(function () {
                   next(ret);
               }, 0);
           }
}

And then the memoizer can be used in conjunction with it:

function plusOne(val) {
    return val+1;
}

var memoPlusOne = memoize(plusOne);
var cpsMemPlusOne = cpsMaker(memoPlusOne);

cpsMemPlusOne(3,function(n){console.log(n)});

The point is to separate the memoization of the transform from the CPS construction.

Thank you for introducing the idea of memoized CPS; even if this answer is rubbish, it has been an eye-opener for me!

查看更多
登录 后发表回答