在调用之前按顺序完成所有函数参数

sim*_*son 1 javascript functional-programming frp

我试图理解以下zip函数(尤其是调用函数)如何变得更加实用.我得到的问题是,invoke方法必须等待左侧和右侧都可以在它调度值之前填充.必须按顺序调用这些值,以便压缩正确的值,否则我会考虑使用curry/partial函数来实现此目的.

有什么我可以使用可以消除这种阻碍.

function zip(state, a, b) {
    var left = [];
    var right = [];

    function invoke() {
        if (left.length > 0 && right.length > 0) {
            state([left.shift(), right.shift()]);
        }
    }

    a.foreach(function(v) {
        left.push(v);
        invoke();
    });

    b.foreach(function(v) {
        right.push(v);
        invoke();
    });
}
Run Code Online (Sandbox Code Playgroud)

Bellow是满足zip功能的简单例子.

function Stream() {
    var env = this;
    env.subs = [];
    env.id = setInterval(function() {
        env.subs.forEach(function(f) {
            f(Math.random()); 
        });
    }, ((Math.random() * 100) + 500) | 0);
}
Stream.prototype.foreach = function(f) {
    this.subs.push(f);
}
zip(function(v) {
    console.log(v);
}, new Stream(), new Stream());
Run Code Online (Sandbox Code Playgroud)

额外:删除可变数组.

Ber*_*rgi 5

如果Stream有一种iterator接口,将第一个元素中的列表和后续元素分开(比如构建Haskell列表,你似乎知道它们),那么一个更实用的方法是可能的.

我知道这个代码起初更复杂(并且至少更长),但使用结构会更方便:

function Promise(resolver) {
    // you know better promise libs of course
    // this one is not even monadic
    var subs = [],
        res = null;
    resolver(function resolve() {
        res = arguments;
        while (subs.length) subs.shift().apply(null, res);
    });
    this.onData = function(f) {
        if (res)
            f.apply(null, res);
        else
            subs.push(f);
        return this;
    };
}
Promise.all = function() {
    var ps = Array.prototype.concat.apply([], arguments);
    return new Promise(function(resolve) {
        var res = [],
            l = ps.length;
        ps.forEach(function(p, i) {
            p.onData(function() {
                while(res.length < arguments.length) res.push([]);
                for (var j=0; j<arguments.length; j++)
                    res[j][i] = arguments[j];
                if (--l == 0)
                    resolve.apply(null, res);
            });
        });
    });
};
Run Code Online (Sandbox Code Playgroud)
function Stream() {
    // an asynchronous (random) list
    var that = this,
        interval = (Math.random() * 100 + 500) | 0;
    this.first = new Promise(function create(resolve) {
        that.id = setTimeout(function() {
            resolve(Math.random(), new Promise(create));
        }, interval);
    });
}
// this is how to consume a stream:
Stream.prototype.forEach = function(f) {
    this.first.onData(function fire(res, next) {
        f(res);
        next.onData(fire);
    });
    return this;
};
Stream.prototype.end = function() { clearTimeout(this.id); return this; };
Run Code Online (Sandbox Code Playgroud)

但现在很容易压缩它们:

function zip() {
    var res = Object.create(Stream.prototype); // inherit the Stream interface
    res.first = (function create(firsts) {
        return new Promise(function(resolve) {
            Promise.all(firsts).onData(function(results, nexts) {
                resolve(results, create(nexts));
            });
        });
    })(Array.prototype.map.call(arguments, function(stream) {
        return stream.first;
    }));
    return res;
}
zip(new Stream, new Stream).forEach(console.log.bind(console));
Run Code Online (Sandbox Code Playgroud)

基本上我已经将你的第一个项目等待进入Promise模式,其中Promise.all功能并行等待,并且你的可变结果数组成为嵌套的promises列表.而且我通过使所有函数都可以使用任意数量的参数来避免代码重复(for leftright).