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)
额外:删除可变数组.
如果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 left和right).