注意:我开始对此主题进行discussion on Github的访问。
我有一个 zip 函数,现在输入的是相同类型T
的可迭代对象。我想为任意混合输入类型输入此类型,但仍保留匹配的输出类型,例如,如果输入类型[Iterable<T>, Iterable<U>]
我希望输出类型为Iterable<[T, U]>
。可以为任意输入大小使用此功能吗?我基本上要说的是,如果您将此类型列表作为输入,则将其作为输出。
这是我的 zip 的当前版本:
export function *zip<T>(...iterables:Array<Iterable<T>>): Iterable<Array<T>> {
const iterators = iterables.map(iterable => iter(iterable));
while(true){
const items = iterators.map(iterator => iterator.next());
if (items.some(item => item.done)){
return;
}
yield ((items.map(item => { return item.value }): Array<any>): Array<T>);
}
}
export function *iter<T>(iterable:Iterable<T>): Iterator<T> {
yield* iterable;
}
当前best solution由AndrewSouthpaw开发:
declare function zip<A, B>(Iterable<A>, Iterable<B>): Iterable<[A, B]>;
declare function zip<A, B, C>(Iterable<A>, Iterable<B>, Iterable<C>): Iterable<[A, B, C]>;
declare function zip<A, B, C, D>(Iterable<A>, Iterable<B>, Iterable<C>, Iterable<D>): Iterable<[A, B, C, D]>;
export function *zip<T>(...iterables:Array<Iterable<T>>): Iterable<Array<T>> {
const iterators = iterables.map(iterable => iter(iterable));
while(true){
const items = iterators.map(iterator => iterator.next());
if (items.some(item => item.done)){
return;
}
yield ((items.map(item => { return item.value }): Array<any>): Array<T>);
}
}
使用4、3或2个可迭代对象进行调用时,它按预期方式工作,使用5个或更多参数进行调用时,流程仅表示zip只能使用4个或更少的参数进行调用。当然,我们可以添加任意数量的函数签名,以使其适用于5、6或任意数量的N个参数,但这将需要声明N个不同的签名(这有点丑陋)。另一方面,这种策略不允许有无数个参数(就像散布运算符一样)。我还在寻找。
这提出了一个更普遍的问题,是否存在任何语言?
我真的感觉这可以在理论上完成(不一定要顺其自然),另一方面,我不记得我已经/看到过的静态类型语言(我也会有兴趣看到以任何语言进行的这种类型检查)。
更具体地说,我的感觉是,如果您有一个类型检查系统,其中(根据定义)所有类型都是静态已知的(任何变量的类型均为x
),则函数{{1 }}总是在已知类型f: Array<Iterable<x>> -> Iterable<Array<x>>
上调用。因此,我们应该能够静态地确定给定x
将返回哪种类型f
(x
是单个泛型类型还是泛型类型列表)。
对于函数本身也是如此,如果您将类型x
作为输入,那么您只需要检查函数是否保留类型x
。
也许这需要在某些语言中递归定义,这也很有趣。
答案 0 :(得分:2)
我们只能通过覆盖函数签名声明来完成此操作。这可能会有所帮助:
declare function zip<A, B>(Iterable<A>, Iterable<B>): Iterable<[A, B]>
declare function zip<A, B, C>(Iterable<A>, Iterable<B>, Iterable<C>): Iterable<[A, B, C]>
declare function zip<A, B, C, D>(Iterable<A>, Iterable<B>, Iterable<C>, Iterable<D>): Iterable<[A, B, C, D]>
export function zip(a, b, c, d) {
/* ... */
}
答案 1 :(得分:0)
这是有效的解决方案。一切归功于Flow团队的jbrown215,他在这里找到了using $ReadOnlyArray<mixed>
的想法:
export function *zip<T: $ReadOnlyArray<mixed>>(...iterables:Array<Iterable<T>>): Iterable<Array<T>> {
const iterators = iterables.map(iterable => iter(iterable));
while(true){
const items = iterators.map(iterator => iterator.next());
if (items.some(item => item.done)){
return;
}
yield ((items.map(item => { return item.value }): Array<any>): Array<T>);
}
}
export function *iter<T>(iterable:Iterable<T>): Iterator<T> {
yield* iterable;
}